├── .gitignore ├── LICENSE ├── Makefile ├── README.md └── src ├── Makefile ├── atom.hpp ├── colormap.hpp ├── connection.hpp ├── core.hpp ├── cursor.hpp ├── drawable.hpp ├── event.hpp ├── examples ├── Makefile ├── demo_01.cpp └── demo_02.cpp ├── flags.makefile ├── font.hpp ├── fontable.hpp ├── gcontext.hpp ├── generic.hpp ├── generic ├── error.hpp ├── event.hpp ├── extension.hpp ├── factory.hpp ├── input_iterator_adapter.hpp ├── iterator_traits.hpp ├── reply_iterator.hpp ├── request.hpp ├── resource.hpp └── signature.hpp ├── pixmap.hpp ├── proto ├── Makefile ├── TODO ├── accessor.py ├── cpp_client.py ├── cppcookie.py ├── cpperror.py ├── cppevent.py ├── cppreply.py ├── cpprequest.py ├── extensionclass.py ├── interfaceclass.py ├── objectclass.py ├── parameter.py ├── resource_classes.py └── utils.py ├── tests ├── .gitignore ├── Makefile ├── README.md ├── callable.cpp ├── error_test.cpp ├── event.cpp ├── iterator.cpp ├── requests.cpp ├── resource.cpp ├── sizeof.cpp ├── template.cpp ├── test.cpp ├── xlib-test.cpp ├── xlib.cpp └── xproto.cpp ├── valueparam.hpp ├── window.hpp └── xpp.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | .clang_complete 2 | *.o 3 | *.swp 4 | *.gch 5 | *.d 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Jochen Keil 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | ${MAKE} -C src/proto 3 | 4 | examples: 5 | ${MAKE} -C src/examples 6 | 7 | .PHONY: ${DIRS} 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xpp - A C++11 RAII wrapper for XCB 2 | 3 | ## Synopsis 4 | 5 | XPP is a header only C++11 6 | [RAII](https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) 7 | wrapper around [X protocol C-language Binding 8 | (XCB)](http://xcb.freedesktop.org). Pointers to dynamically allocated memory, 9 | such as events and errors are wrapped in std::shared_ptr. 10 | 11 | Furthermore, interfaces for connection and resource types are provided to 12 | facilitate the creation of custom classes. For convenience, a connection class 13 | and several basic resource type classes are readily available. 14 | 15 | XPP makes widespread use of the 16 | [Curiously Recurring Template Pattern (CRTP)](https://en.wikibooks.org/wiki/More_C++_Idioms/Curiously_Recurring_Template_Pattern) 17 | to avoid overhead through dynamic dispatch. Hence, most interfaces are 18 | implicitly defined. 19 | 20 | ## Prerequisites 21 | 22 | * Python 2 23 | * GCC >= 4.8 (or Clang >= 3.3, untested) 24 | * libxcb 25 | 26 | ## Quick Start 27 | 28 | ``` 29 | git clone https://github.com/jrk-/xpp 30 | cd xpp 31 | make 32 | make examples 33 | cd src/examples 34 | for demo in demo_*; do ./${demo}; done 35 | ``` 36 | 37 | ## Documentation 38 | 39 | ### General 40 | 41 | The bindings can be generated by calling `make` in the top level directory. If 42 | this fails, check the [`XCBGEN`](src/proto/Makefile#L38) and 43 | [`PROTODIR`](src/proto/Makefile#L39) variables in 44 | [src/proto/Makefile](src/proto/Makefile). These need to point to the `xcbgen` 45 | python package and the xml protocol description respectively. 46 | 47 | Once the bindings are generated they can be used by including 48 | [src/xpp.hpp](src/xpp.hpp). If an extensions is required, it needs to be 49 | included additionally. For example, the RandR extension is available through 50 | `proto/randr.hpp`, the Damage extension through `proto/damage.hpp`, etc. 51 | 52 | Recent (and working) examples can be found in [src/examples](src/examples). 53 | To compile them, call `make examples` in the `xpp` directory or just `make` in 54 | [src/examples](src/examples). 55 | 56 | ### Requests 57 | 58 | Requests obey this naming scheme: `xpp:: ExtensionName :: RequestName`. 59 | 60 | ##### Examples: 61 | 62 | Core X protocol: 63 | `MapWindow`: `xcb_map_window{,_checked}` -> `xpp::x::map_window{,_checked}` 64 | `InternAtom`: `xcb_intern_atom{,_checked}` -> `xpp::x::intern_atom{,_unchecked}` 65 | 66 | RandR protocol: 67 | `SelectInput`: `xcb_randr_select_input{,_checked}` -> `xpp::randr::select_input{,_checked}` 68 | `QueryVersion`: `xcb_randr_query_version{,_unchecked}` -> `xpp::randr::query_version{,_unchecked}` 69 | 70 | ##### Default Parameter 71 | 72 | All `xcb_timestamp_t` parameters are alternatively available with a default 73 | value of `XCB_TIME_CURRENT_TIME`. 74 | 75 | ##### Parameter Lists 76 | 77 | Requests which take a list of values as parameters can be used with any STL 78 | container by passing in Iterators. Example: 79 | 80 | ``` 81 | std::string string_example = "example string"; 82 | // std::list list_example = { 'a', 'b', 'c' }; 83 | // std::map map_example = { {0, 'a'}, {1, 'b'}, {2, 'c'} }; 84 | xpp::x::change_property_checked(c, XCB_PROP_MODE_REPLACE, window, 85 | atom, XCB_ATOM_STRING, 8, 86 | string_example.begin(), string_example.end()); 87 | // list_example.begin(), list_example.end()); 88 | // for associative containers the value (std::pair<..>::second_type) will be used 89 | // map_example.begin(), map_example.end()); 90 | ``` 91 | 92 | ### Replies 93 | 94 | XCB returns replies only when they are explicitely queried. With XPP this is not 95 | necessary anymore, because the operators for accessing the reply are overloaded. 96 | 97 | For example, getting the reply for the `InternAtom` request is as simple as this: 98 | 99 | ``` 100 | auto reply = xpp::x::intern_atom(connection, true, "MY_ATOM_NAME"); 101 | // do some other stuff .. 102 | // latency hiding is still effective, because the call to 103 | // xcb_intern_atom_reply happens but now in operator->() 104 | xcb_atom_t atom = reply->atom; 105 | ``` 106 | 107 | #### Member Accessors 108 | 109 | ##### Simple Types 110 | 111 | Primitive types like `xcb_window_t`, `xcb_atom_t`, etc. can be accessed either 112 | directly through the overloaded `operator->()` or via a method which has the 113 | same name as the member. These methods are templated with a default template 114 | type of the native type. Any type which is default constructible from the native 115 | type or a connection and the native type can be specified as template argument. 116 | 117 | Examples: 118 | 119 | ``` 120 | xcb_window_t w1 = reply->member; 121 | xcb_window_t w2 = reply.member(); // default template parameter is xcb_window_t 122 | xpp::window w3 = reply.member(); 123 | ``` 124 | 125 | ##### List Types 126 | 127 | Lists (e.g. the result for `QueryTree`) are accessible through iterators. The 128 | value type is templated, with the default being the native data type. 129 | 130 | Example: 131 | 132 | ``` 133 | auto tree = xpp::x::query_tree(c, window); 134 | 135 | // default template type: xcb_window_t 136 | for (auto && child : tree.children()) { 137 | // child has type xcb_window_t 138 | } 139 | 140 | // xpp::window is constructible with a connection and xcb_window_t 141 | // other types which are default-constructible with either the value type 142 | // (e.g. xcb_window_t) or a connection & the value type are possible, too 143 | for (auto && child : tree.children()) { 144 | // child has type xpp::window 145 | } 146 | ``` 147 | 148 | Caveat: Some requests (in particular `GetProperty`) return an untyped array of 149 | bytes (`void *`). To access the desired data type, a template type must be 150 | specified. For constructible types a type trait must be implemented, like so: 151 | 152 | ``` 153 | struct my_type { 154 | my_type(const xcb_window_t &); 155 | // .. 156 | }; 157 | 158 | namespace xpp { namespace generic { 159 | struct traits { 160 | typedef xcb_atom_t type; 161 | }; 162 | }; }; // namespace xpp::generic 163 | ``` 164 | 165 | ### Errors 166 | 167 | XCB offers four different variants of request functions. 168 | 169 | ##### Requests without a reply: 170 | 171 | * Error delivered through event queue: `xcb_void_cookie_t xcb_request(...)` 172 | 173 | * Error can be checked immediately with `xcb_request_check(xcb_connection_t *, xcb_void_cookie_t)`: `xcb_void_cookie_t xcb_request_checked(...)` 174 | 175 | ##### Requests with reply: 176 | 177 | * Error can be checked when getting the reply: 178 | `xcb_request_reply_t * xcb_request_reply(xcb_connection_t *, xcb_request_cookie_t, xcb_generic_error_t **)`: 179 | `xcb_request_cookie_t xcb_request(...)` 180 | 181 | * Error delivered through event queue: `xcb_request_cookie_t xcb_request_unchecked(...)` 182 | 183 | For more information on this, refer to [xcb-requests (3)](http://www.x.org/releases/current/doc/man/man3/xcb-requests.3.xhtml). 184 | 185 | With xpp errors are either thrown as `std::shared_ptr` or 186 | typed as `xpp:: extension ::error:: error_type`, e.g. `xpp::x::error::value`. 187 | 188 | The latter are based upon `xpp::generic::error` (which inherits from 189 | `std::runtime_error`) and come with a textual error description which is 190 | accessible through the `what()` method. 191 | 192 | For typed errors it is necessary to use a connection class which implements the 193 | appropriate error dispatching. The supplied `xpp::connection` class already does 194 | this. If no error dispatcher are available (e.g. when used with 195 | `xcb_connection_t *`), then a simply `std::shared_ptr` 196 | will be thrown. 197 | 198 | ### Events 199 | 200 | Events returned by the event producing methods (`wait_for_event`, 201 | `poll_for_event`, etc.) from `xpp::core` and `xpp::connection` are encapsulated 202 | as `std::shared_ptr`. 203 | 204 | For additional convenience typed events are available. An event type is based on 205 | `xpp::generic::event`. The general structure for a typed event is 206 | 207 | `xpp::` Extension `::event::` EventName 208 | 209 | Examples: 210 | 211 | ``` 212 | xpp::x::event::key_press 213 | xpp::randr::event::notify 214 | xpp::damage::event::notify 215 | ``` 216 | 217 | Events can be converted from `std::shared_ptr` to a typed 218 | event by either using an event dispatcher functor (e.g. 219 | `xpp::x::event::dispatcher`) or by using the event registry described below. 220 | 221 | ##### Registry 222 | 223 | The event registry `xpp::event::registry` can be 224 | used to connect events and event handlers. 225 | 226 | First, a registry object for the desired `Connection` type and `Extensions` is 227 | necessary. 228 | 229 | Then, arbitrary objects, which implement the `xpp::event::sink<..>` interface 230 | need to be attached for event handling by calling the `attach()` method. 231 | It takes two parameters. The first one specifies the priority, in case there are 232 | more than one event handler for this event. Handlers with lower priorities are 233 | called first. The second one is a pointer to an object which implements the 234 | `xpp::event::sink<..>` interface. 235 | 236 | For a detailed example, take a look at this [demo](src/examples/demo_01.cpp). 237 | 238 | ### Interfaces 239 | 240 | Interfaces for creating custom types are available. 241 | 242 | ##### Connection 243 | 244 | For every extension a "connection" interface, called 245 | `xpp:: ExtensionName ::interface` 246 | is available. 247 | 248 | These encapsulate every request for a particular extension. The `Derived` 249 | template parameter specifies the class which wants to derive from the interface. 250 | The `Derived` class must provide a method `Connection connection();`. 251 | 252 | Examples: 253 | 254 | ``` 255 | xpp::x::interface 256 | xpp::randr::interface 257 | xpp::damage::interface 258 | etc. 259 | ``` 260 | 261 | For a customizable default implementation, take a look at the `xpp::connection` 262 | class described [here](#default-type-connection). 263 | 264 | ##### Resources 265 | 266 | In addition, interfaces for basic resource types like `xcb_window_t`, 267 | `xcb_atom_t`, `xcb_gcontext_t`, etc. are available. 268 | 269 | Again, the naming scheme follows the format 270 | `xpp:: ExtensionName :: XidType ` 271 | 272 | Despite the `connection()` method described [here](#interface-connection), 273 | `Derived` needs to implement a `resource()` method which returns a xid which 274 | will be passed as parameter to the encapsulated requests. 275 | 276 | Examples: 277 | 278 | ``` 279 | xpp::x::window 280 | xpp::randr::output 281 | xpp::render::glyphset 282 | etc. 283 | ``` 284 | 285 | ### Default Types 286 | 287 | ##### Connection 288 | 289 | `xpp::connection` provides a default 290 | implementation of the [core connection methods](src/core.hpp), the core 291 | X protocol and error handling facilities. In addition, it is implicitly 292 | convertible to `xcb_connection_t *`, hence it can be used seamlessly with XCB 293 | functions. The connection can be augmented with additional extension methods, by 294 | specifying the desired extensions as template parameters. 295 | 296 | Example: 297 | 298 | `typedef xpp::connection my_connection;` 299 | 300 | ##### Resources 301 | 302 | For the basic resource types like `Drawable`, `Window`, `Pixmap`, `Atom`, 303 | `Colormap`, `Cursor`, `Font`, `Fontable` and `GContext` wrapper types exist. 304 | They are named `xpp::drawable`, `xpp::window`, etc. 305 | 306 | Each is based upon xpp::generic::resource and provides the core X protocol 307 | interface for the encapsulated resource type. If the resource can be acquired 308 | from the X server (e.g. with `CreateWindow`) then a named constructor is 309 | available (e.g. `create_window` for `xpp::window`). 310 | 311 | Resources acquired through the named constructors are reference counted. When 312 | their lifetime expires, the resource handle will automatically be freed on the 313 | server. No call to destroy or free functions is necessary. 314 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | CXXFLAGS=-std=c++11 -Wall -O3 2 | 3 | HPPSRCS=$(shell find . -maxdepth 1 -name '*.hpp') 4 | HPPOBJS=$(HPPSRCS:%.hpp=%.hpp.gch) 5 | 6 | all: ${DIRS} ${HPPOBJS} 7 | 8 | %.hpp.gch: %.hpp 9 | ${CXX} ${CXXFLAGS} -MMD -c $< 10 | 11 | -include $(HPPSRCS:%.hpp=%.d) 12 | include flags.makefile 13 | 14 | version: ${LIBS} 15 | @echo -e "\nGCC version:" 16 | @gcc -v 2>&1 17 | 18 | ${LIBS}: 19 | @printf "%-20s" "$@:" 20 | @pkg-config --modversion $@ 21 | 22 | clean: 23 | rm -f ${HPPOBJS} 24 | 25 | .PHONY: clean version 26 | -------------------------------------------------------------------------------- /src/atom.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_ATOM_HPP 2 | #define XPP_ATOM_HPP 3 | 4 | #include "proto/x.hpp" 5 | #include "generic/resource.hpp" 6 | 7 | namespace xpp { 8 | 9 | template class ... Interfaces> 10 | class atom 11 | : public xpp::generic::resource 13 | { 14 | protected: 15 | using base = xpp::generic::resource; 16 | 17 | public: 18 | using base::base; 19 | using base::operator=; 20 | }; 21 | 22 | namespace generic { 23 | 24 | template class ... Interfaces> 25 | struct traits> 26 | { 27 | typedef xcb_atom_t type; 28 | }; 29 | 30 | }; // namespace generic 31 | 32 | }; // namespace xpp 33 | 34 | #endif // XPP_ATOM_HPP 35 | -------------------------------------------------------------------------------- /src/colormap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_COLORMAP_HPP 2 | #define XPP_COLORMAP_HPP 3 | 4 | #include "proto/x.hpp" 5 | #include "generic/resource.hpp" 6 | 7 | namespace xpp { 8 | 9 | template class ... Interfaces> 10 | class colormap 11 | : public xpp::generic::resource 13 | { 14 | protected: 15 | using base = xpp::generic::resource; 17 | 18 | template 19 | colormap(C && c, Create && create, Destroy && destroy) 20 | : base(base::make(std::forward(c), 21 | std::forward(create), 22 | std::forward(destroy))) 23 | {} 24 | 25 | public: 26 | using base::base; 27 | using base::operator=; 28 | 29 | template 30 | static 31 | colormap 32 | create(C && c, uint8_t alloc, xcb_window_t window, xcb_visualid_t visual) 33 | { 34 | return colormap( 35 | std::forward(c), 36 | [&](const Connection & c, const xcb_colormap_t & colormap) 37 | { 38 | xpp::x::create_colormap(c, alloc, colormap, window, visual); 39 | }, 40 | [&](const Connection & c, const xcb_colormap_t & colormap) 41 | { 42 | xpp::x::free_colormap(c, colormap); 43 | }); 44 | } 45 | 46 | template 47 | static 48 | colormap 49 | create_checked(C && c, uint8_t alloc, 50 | xcb_window_t window, xcb_visualid_t visual) 51 | { 52 | return colormap( 53 | std::forward(c), 54 | [&](const Connection & c, const xcb_colormap_t & colormap) 55 | { 56 | xpp::x::create_colormap_checked(c, alloc, colormap, window, visual); 57 | }, 58 | [&](const Connection & c, const xcb_colormap_t & colormap) 59 | { 60 | xpp::x::free_colormap_checked(c, colormap); 61 | }); 62 | } 63 | }; 64 | 65 | namespace generic { 66 | 67 | template class ... Interfaces> 68 | struct traits> 69 | { 70 | typedef xcb_colormap_t type; 71 | }; 72 | 73 | }; // namespace generic 74 | 75 | }; // namespace xpp 76 | 77 | #endif // XPP_COLORMAP_HPP 78 | -------------------------------------------------------------------------------- /src/connection.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_CONNECTION_HPP 2 | #define XPP_CONNECTION_HPP 3 | 4 | #include "core.hpp" 5 | #include "generic/factory.hpp" 6 | 7 | #include "proto/x.hpp" 8 | 9 | namespace xpp { 10 | 11 | namespace detail { 12 | 13 | template 14 | class interfaces 15 | : public xpp::x::extension::interface, Connection> 16 | , public Extensions::template interface, Connection> ... 17 | { 18 | public: 19 | Connection 20 | connection(void) const 21 | { 22 | return static_cast(*this); 23 | } 24 | }; // class interfaces 25 | 26 | }; // namespace detail 27 | 28 | template 29 | class connection 30 | : public xpp::core 31 | , public xpp::generic::error_dispatcher 32 | , public detail::interfaces, Extensions ...> 33 | // private interfaces: extensions and error_dispatcher 34 | , private xpp::x::extension 35 | , private xpp::x::extension::error_dispatcher 36 | , private Extensions ... 37 | , private Extensions::error_dispatcher ... 38 | { 39 | protected: 40 | typedef connection self; 41 | 42 | 43 | public: 44 | template 45 | explicit 46 | connection(Parameters && ... parameters) 47 | : xpp::core::core(std::forward(parameters) ...) 48 | , detail::interfaces, Extensions ...>(*this) 49 | , Extensions(static_cast(*this)) ... 50 | , Extensions::error_dispatcher(static_cast(*this).get()) ... 51 | { 52 | m_root_window = screen_of_display(default_screen())->root; 53 | } 54 | 55 | virtual 56 | ~connection(void) 57 | {} 58 | 59 | virtual 60 | operator xcb_connection_t *(void) const 61 | { 62 | return *(static_cast(*this)); 63 | } 64 | 65 | void 66 | operator()(const std::shared_ptr & error) const 67 | { 68 | check(error); 69 | } 70 | 71 | template 72 | const Extension & 73 | extension(void) const 74 | { 75 | return static_cast(*this); 76 | } 77 | 78 | // TODO 79 | // virtual operator Display * const(void) const 80 | // { 81 | // } 82 | 83 | template 84 | Window 85 | root(void) 86 | { 87 | using make = xpp::generic::factory::make; 88 | return make()(*this, m_root_window); 89 | } 90 | 91 | template 92 | Window 93 | root(void) const 94 | { 95 | using make = xpp::generic::factory::make; 96 | return make()(*this, m_root_window); 97 | } 98 | 99 | virtual 100 | shared_generic_event_ptr 101 | wait_for_event(void) const 102 | { 103 | try { 104 | return core::wait_for_event(); 105 | } catch (const std::shared_ptr & error) { 106 | check(error); 107 | } 108 | // re-throw any exception caused by wait_for_event 109 | throw; 110 | } 111 | 112 | virtual 113 | shared_generic_event_ptr 114 | wait_for_special_event(xcb_special_event_t * se) const 115 | { 116 | try { 117 | return core::wait_for_special_event(se); 118 | } catch (const std::shared_ptr & error) { 119 | check(error); 120 | } 121 | // re-throw any exception caused by wait_for_special_event 122 | throw; 123 | } 124 | 125 | private: 126 | xcb_window_t m_root_window; 127 | 128 | template 129 | void 130 | check(const std::shared_ptr & error) const 131 | { 132 | check(error); 133 | check(error); 134 | } 135 | 136 | template 137 | void 138 | check(const std::shared_ptr & error) const 139 | { 140 | using error_dispatcher = typename Extension::error_dispatcher; 141 | auto & dispatcher = static_cast(*this); 142 | dispatcher(error); 143 | } 144 | }; // class connection 145 | 146 | template<> 147 | template 148 | connection<>::connection(Parameters && ... parameters) 149 | : xpp::core::core(std::forward(parameters) ...) 150 | , detail::interfaces>(*this) 151 | { 152 | m_root_window = screen_of_display(static_cast(*this).default_screen())->root; 153 | } 154 | 155 | }; // namespace xpp 156 | 157 | #endif // XPP_CONNECTION_HPP 158 | -------------------------------------------------------------------------------- /src/core.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_CORE_HPP 2 | #define XPP_CORE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace xpp { 9 | 10 | class connection_error 11 | : public std::runtime_error 12 | { 13 | public: 14 | connection_error(uint8_t code, const std::string & description) 15 | : std::runtime_error(description + "(" + std::to_string(code) + ")") 16 | , m_code(code) 17 | , m_description(description) 18 | {} 19 | 20 | uint8_t 21 | code(void) 22 | { 23 | return m_code; 24 | } 25 | 26 | std::string 27 | description(void) 28 | { 29 | return m_description; 30 | } 31 | 32 | protected: 33 | uint8_t m_code; 34 | std::string m_description; 35 | }; 36 | 37 | class core 38 | { 39 | protected: 40 | using shared_generic_event_ptr = std::shared_ptr; 41 | 42 | int m_screen = 0; 43 | // reference counting for xcb_connection_t 44 | std::shared_ptr m_c; 45 | 46 | shared_generic_event_ptr 47 | dispatch(const std::string & producer, xcb_generic_event_t * event) const 48 | { 49 | if (event) { 50 | if (event->response_type == 0) { 51 | throw std::shared_ptr( 52 | reinterpret_cast(event)); 53 | } 54 | 55 | return shared_generic_event_ptr(event, std::free); 56 | } 57 | 58 | check_connection(); 59 | throw std::runtime_error(producer + " failed"); 60 | } 61 | 62 | public: 63 | explicit 64 | core(xcb_connection_t * c) 65 | : m_c(std::shared_ptr(c, [](...) {})) 66 | {} 67 | 68 | template 69 | explicit 70 | core(xcb_connection_t * (*Connect)(ConnectionParameter ...), 71 | ConnectionParameter ... connection_parameter) 72 | : m_c(std::shared_ptr( 73 | Connect(connection_parameter ...), 74 | [&](void *) { disconnect(); })) 75 | {} 76 | 77 | // xcb_connect (const char *displayname, int *screenp) 78 | explicit 79 | core(const std::string & displayname = "") 80 | : core(xcb_connect, displayname.c_str(), &m_screen) 81 | {} 82 | 83 | // xcb_connect_to_fd (int fd, xcb_auth_info_t *auth_info) 84 | explicit 85 | core(int fd, xcb_auth_info_t * auth_info) 86 | : core(xcb_connect_to_fd, fd, auth_info) 87 | {} 88 | 89 | // xcb_connect_to_display_with_auth_info ( 90 | // const char *display, xcb_auth_info_t *auth, int *screen) 91 | explicit 92 | core(const std::string & display, xcb_auth_info_t * auth) 93 | : core(xcb_connect_to_display_with_auth_info, 94 | display.c_str(), auth, &m_screen) 95 | {} 96 | 97 | virtual 98 | ~core(void) 99 | {} 100 | 101 | virtual 102 | xcb_connection_t * 103 | operator*(void) const 104 | { 105 | return m_c.get(); 106 | } 107 | 108 | virtual 109 | operator xcb_connection_t *(void) const 110 | { 111 | return m_c.get(); 112 | } 113 | 114 | virtual 115 | int 116 | default_screen(void) const 117 | { 118 | return m_screen; 119 | } 120 | 121 | virtual 122 | int 123 | flush(void) const 124 | { 125 | return xcb_flush(m_c.get()); 126 | } 127 | 128 | virtual 129 | uint32_t 130 | get_maximum_request_length(void) const 131 | { 132 | return xcb_get_maximum_request_length(m_c.get()); 133 | } 134 | 135 | virtual 136 | void 137 | prefetch_maximum_request_length(void) const 138 | { 139 | xcb_prefetch_maximum_request_length(m_c.get()); 140 | } 141 | 142 | virtual 143 | shared_generic_event_ptr 144 | wait_for_event(void) const 145 | { 146 | return dispatch("wait_for_event", xcb_wait_for_event(m_c.get())); 147 | } 148 | 149 | virtual 150 | shared_generic_event_ptr 151 | poll_for_event(void) const 152 | { 153 | return shared_generic_event_ptr(xcb_poll_for_event(m_c.get())); 154 | } 155 | 156 | virtual 157 | shared_generic_event_ptr 158 | poll_for_queued_event(void) const 159 | { 160 | return shared_generic_event_ptr(xcb_poll_for_queued_event(m_c.get())); 161 | } 162 | 163 | virtual 164 | shared_generic_event_ptr 165 | poll_for_special_event(xcb_special_event_t * se) const 166 | { 167 | return shared_generic_event_ptr(xcb_poll_for_special_event(m_c.get(), se)); 168 | } 169 | 170 | // virtual 171 | // shared_generic_event_ptr 172 | // poll_for_special_event(const std::shared_ptr & se) const 173 | // { 174 | // return poll_for_special_event(se.get()); 175 | // } 176 | 177 | virtual 178 | shared_generic_event_ptr 179 | wait_for_special_event(xcb_special_event_t * se) const 180 | { 181 | return dispatch("wait_for_special_event", 182 | xcb_wait_for_special_event(m_c.get(), se)); 183 | } 184 | 185 | // virtual 186 | // shared_generic_event_ptr 187 | // wait_for_special_event(const std::shared_ptr & se) const 188 | // { 189 | // return wait_for_special_event(se.get()); 190 | // } 191 | 192 | // xcb_special_event_t has incomplete type -> no std::shared_ptr 193 | virtual 194 | xcb_special_event_t * 195 | register_for_special_xge(xcb_extension_t * ext, 196 | uint32_t eid, 197 | uint32_t * stamp) const 198 | { 199 | return xcb_register_for_special_xge(m_c.get(), ext, eid, stamp); 200 | } 201 | 202 | virtual 203 | void 204 | unregister_for_special_event(xcb_special_event_t * se) const 205 | { 206 | xcb_unregister_for_special_event(m_c.get(), se); 207 | } 208 | 209 | virtual 210 | std::shared_ptr 211 | request_check(xcb_void_cookie_t cookie) const 212 | { 213 | return std::shared_ptr( 214 | xcb_request_check(m_c.get(), cookie)); 215 | } 216 | 217 | virtual 218 | void 219 | discard_reply(unsigned int sequence) const 220 | { 221 | xcb_discard_reply(m_c.get(), sequence); 222 | } 223 | 224 | // The result must not be freed. 225 | // This storage is managed by the cache itself. 226 | virtual 227 | const xcb_query_extension_reply_t * 228 | get_extension_data(xcb_extension_t * ext) const 229 | { 230 | return xcb_get_extension_data(m_c.get(), ext); 231 | } 232 | 233 | virtual 234 | void 235 | prefetch_extension_data(xcb_extension_t * ext) const 236 | { 237 | xcb_prefetch_extension_data(m_c.get(), ext); 238 | } 239 | 240 | virtual 241 | const xcb_setup_t * 242 | get_setup(void) const 243 | { 244 | return xcb_get_setup(m_c.get()); 245 | } 246 | 247 | virtual 248 | int 249 | get_file_descriptor(void) const 250 | { 251 | return xcb_get_file_descriptor(m_c.get()); 252 | } 253 | 254 | virtual 255 | int 256 | connection_has_error(void) const 257 | { 258 | return xcb_connection_has_error(m_c.get()); 259 | } 260 | 261 | virtual 262 | void 263 | disconnect(void) const 264 | { 265 | xcb_disconnect(m_c.get()); 266 | } 267 | 268 | // hostname, display, screen 269 | virtual 270 | std::tuple 271 | parse_display(const std::string & name) const 272 | { 273 | int screen = 0; 274 | int display = 0; 275 | char * host = NULL; 276 | std::string hostname; 277 | 278 | xcb_parse_display(name.c_str(), &host, &display, &screen); 279 | if (host != NULL) { 280 | hostname = std::string(host); 281 | } 282 | 283 | return std::make_tuple(hostname, display, screen); 284 | } 285 | 286 | virtual 287 | uint32_t 288 | generate_id(void) const 289 | { 290 | return xcb_generate_id(m_c.get()); 291 | } 292 | 293 | xcb_screen_t * 294 | screen_of_display(int screen) 295 | { 296 | xcb_screen_iterator_t iter; 297 | 298 | iter = xcb_setup_roots_iterator(xcb_get_setup(m_c.get())); 299 | for (; iter.rem; --screen, xcb_screen_next(&iter)) 300 | if (screen == 0) 301 | return iter.data; 302 | 303 | return NULL; 304 | } 305 | 306 | void 307 | check_connection(void) const 308 | { 309 | switch (xcb_connection_has_error(m_c.get())) { 310 | case XCB_CONN_ERROR: 311 | throw(connection_error( 312 | XCB_CONN_ERROR, "XCB_CONN_ERROR")); 313 | 314 | case XCB_CONN_CLOSED_EXT_NOTSUPPORTED: 315 | throw(connection_error(XCB_CONN_CLOSED_EXT_NOTSUPPORTED, 316 | "XCB_CONN_CLOSED_EXT_NOTSUPPORTED")); 317 | 318 | case XCB_CONN_CLOSED_MEM_INSUFFICIENT: 319 | throw(connection_error(XCB_CONN_CLOSED_MEM_INSUFFICIENT, 320 | "XCB_CONN_CLOSED_MEM_INSUFFICIENT")); 321 | 322 | case XCB_CONN_CLOSED_REQ_LEN_EXCEED: 323 | throw(connection_error(XCB_CONN_CLOSED_REQ_LEN_EXCEED, 324 | "XCB_CONN_CLOSED_REQ_LEN_EXCEED")); 325 | 326 | case XCB_CONN_CLOSED_PARSE_ERR: 327 | throw(connection_error(XCB_CONN_CLOSED_PARSE_ERR, 328 | "XCB_CONN_CLOSED_PARSE_ERR")); 329 | 330 | case XCB_CONN_CLOSED_INVALID_SCREEN: 331 | throw(connection_error(XCB_CONN_CLOSED_INVALID_SCREEN, 332 | "XCB_CONN_CLOSED_INVALID_SCREEN")); 333 | }; 334 | } 335 | }; // class core 336 | 337 | }; // namespace xpp 338 | 339 | #endif // XPP_CORE_HPP 340 | -------------------------------------------------------------------------------- /src/cursor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_CURSOR_HPP 2 | #define XPP_CURSOR_HPP 3 | 4 | #include "proto/x.hpp" 5 | #include "generic/resource.hpp" 6 | 7 | namespace xpp { 8 | 9 | template class ... Interfaces> 10 | class cursor 11 | : public xpp::generic::resource 13 | { 14 | protected: 15 | using base = xpp::generic::resource; 17 | 18 | template 19 | cursor(C && c, Create && create, Destroy && destroy) 20 | : base(base::make(std::forward(c), 21 | std::forward(create), 22 | std::forward(destroy))) 23 | {} 24 | 25 | public: 26 | using base::base; 27 | using base::operator=; 28 | 29 | template 30 | static 31 | cursor 32 | create(C && c, 33 | xcb_pixmap_t source, xcb_pixmap_t mask, 34 | uint16_t fore_red, uint16_t fore_green, uint16_t fore_blue, 35 | uint16_t back_red, uint16_t back_green, uint16_t back_blue, 36 | uint16_t x, uint16_t y) 37 | { 38 | return cursor( 39 | std::forward(c), 40 | [&](Connection & c, const xcb_cursor_t & cursor) 41 | { 42 | xpp::x::create_cursor(c, cursor, 43 | source, mask, 44 | fore_red, fore_green, fore_blue, 45 | back_red, back_green, back_blue, 46 | x, y); 47 | }, 48 | [&](Connection & c, const xcb_cursor_t & cursor) 49 | { 50 | xpp::x::free_cursor(c, cursor); 51 | }); 52 | } 53 | 54 | template 55 | static 56 | cursor 57 | create_checked(C && c, 58 | xcb_pixmap_t source, xcb_pixmap_t mask, 59 | uint16_t fore_red, uint16_t fore_green, uint16_t fore_blue, 60 | uint16_t back_red, uint16_t back_green, uint16_t back_blue, 61 | uint16_t x, uint16_t y) 62 | { 63 | return cursor( 64 | std::forward(c), 65 | [&](Connection & c, const xcb_cursor_t & cursor) 66 | { 67 | xpp::x::create_cursor_checked(c, cursor, 68 | source, mask, 69 | fore_red, fore_green, fore_blue, 70 | back_red, back_green, back_blue, 71 | x, y); 72 | }, 73 | [&](Connection & c, const xcb_cursor_t & cursor) 74 | { 75 | xpp::x::free_cursor_checked(c, cursor); 76 | }); 77 | } 78 | 79 | template 80 | static 81 | cursor 82 | create_glyph(C && c, 83 | xcb_font_t source_font, xcb_font_t mask_font, 84 | uint16_t source_char, uint16_t mask_char, 85 | uint16_t fore_red, uint16_t fore_green, uint16_t fore_blue, 86 | uint16_t back_red, uint16_t back_green, uint16_t back_blue) 87 | { 88 | return cursor( 89 | std::forward(c), 90 | [&](Connection & c, const xcb_cursor_t & cursor) 91 | { 92 | xpp::x::create_glyph_cursor(c, cursor, 93 | source_font, mask_font, 94 | source_char, mask_char, 95 | fore_red, fore_green, fore_blue, 96 | back_red, back_green, back_blue); 97 | }, 98 | [](Connection & c, const xcb_cursor_t & cursor) 99 | { 100 | xpp::x::free_cursor(c, cursor); 101 | }); 102 | } 103 | 104 | template 105 | static 106 | cursor 107 | create_glyph_checked(C && c, 108 | xcb_font_t source_font, xcb_font_t mask_font, 109 | uint16_t source_char, uint16_t mask_char, 110 | uint16_t fore_red, uint16_t fore_green, uint16_t fore_blue, 111 | uint16_t back_red, uint16_t back_green, uint16_t back_blue) 112 | { 113 | return cursor( 114 | std::forward(c), 115 | [&](Connection & c, const xcb_cursor_t & cursor) 116 | { 117 | xpp::x::create_glyph_cursor_checked(c, cursor, 118 | source_font, mask_font, 119 | source_char, mask_char, 120 | fore_red, fore_green, fore_blue, 121 | back_red, back_green, back_blue); 122 | }, 123 | [](Connection & c, const xcb_cursor_t & cursor) 124 | { 125 | xpp::x::free_cursor_checked(c, cursor); 126 | }); 127 | } 128 | }; 129 | 130 | namespace generic { 131 | 132 | template class ... Interfaces> 133 | struct traits> 134 | { 135 | typedef xcb_cursor_t type; 136 | }; 137 | 138 | }; // namespace generic 139 | 140 | }; // namespace xpp 141 | 142 | #endif // XPP_CURSOR_HPP 143 | -------------------------------------------------------------------------------- /src/drawable.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_DRAWABLE_HPP 2 | #define XPP_DRAWABLE_HPP 3 | 4 | #include "proto/x.hpp" 5 | #include "generic/resource.hpp" 6 | 7 | namespace xpp { 8 | 9 | template class ... Interfaces> 10 | class drawable 11 | : public xpp::generic::resource 13 | { 14 | protected: 15 | using base = xpp::generic::resource; 17 | 18 | public: 19 | using base::base; 20 | using base::operator=; 21 | }; 22 | 23 | namespace generic { 24 | 25 | template class ... Interfaces> 26 | struct traits> 27 | { 28 | typedef xcb_drawable_t type; 29 | }; 30 | 31 | }; // namespace generic 32 | 33 | }; // namespace xpp 34 | 35 | #endif // XPP_DRAWABLE_HPP 36 | -------------------------------------------------------------------------------- /src/event.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_EVENT_HPP 2 | #define XPP_EVENT_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "proto/x.hpp" 10 | 11 | #define MAX_PRIORITY UINT32_MAX 12 | 13 | namespace xpp { 14 | 15 | namespace event { 16 | 17 | namespace detail { 18 | 19 | class dispatcher { 20 | public: 21 | virtual ~dispatcher(void) {} 22 | template void dispatch(const Event & e); 23 | }; // namespace dispatcher 24 | 25 | template 26 | class sink : virtual public dispatcher 27 | { 28 | public: 29 | virtual ~sink(void) {} 30 | virtual void handle(const Event &) = 0; 31 | }; 32 | 33 | }; // namespace detail 34 | 35 | template 36 | class sink 37 | : public detail::sink 38 | , public detail::sink ... 39 | {}; 40 | 41 | template 42 | class registry 43 | : public xpp::x::event::dispatcher 44 | , public Extensions::template event_dispatcher ... 45 | { 46 | public: 47 | typedef unsigned int priority; 48 | 49 | template 50 | explicit 51 | registry(C && c) 52 | : xpp::x::event::dispatcher(std::forward(c)) 53 | , Extensions::template event_dispatcher( 54 | std::forward(c), c.template extension()) ... 55 | , m_c(std::forward(c)) 56 | {} 57 | 58 | bool 59 | dispatch(const std::shared_ptr & event) const 60 | { 61 | return dispatch(event); 62 | } 63 | 64 | template 65 | void 66 | attach(priority p, sink * s) 67 | { 68 | attach, Event, Rest ...>(p, s); 69 | } 70 | 71 | template 72 | void 73 | detach(priority p, sink * s) 74 | { 75 | detach, Event, Rest ...>(p, s); 76 | } 77 | 78 | private: 79 | typedef std::multimap priority_map; 80 | 81 | Connection m_c; 82 | std::unordered_map m_dispatchers; 83 | 84 | template 85 | uint8_t opcode(const xpp::x::extension &) const 86 | { 87 | return Event::opcode(); 88 | } 89 | 90 | template 91 | uint8_t opcode(const Extension & extension) const 92 | { 93 | return Event::opcode(extension); 94 | } 95 | 96 | template 97 | uint8_t opcode(void) const 98 | { 99 | return opcode(m_c.template extension()); 100 | } 101 | 102 | template 103 | void 104 | handle(const Event & event) const 105 | { 106 | try { 107 | for (auto & item : m_dispatchers.at(opcode())) { 108 | item.second->dispatch(event); 109 | } 110 | } catch (...) {} 111 | } 112 | 113 | struct handler { 114 | handler(const registry & registry) 115 | : m_registry(registry) 116 | {} 117 | 118 | const registry & m_registry; 119 | 120 | template 121 | void 122 | operator()(const Event & event) const 123 | { 124 | m_registry.handle(event); 125 | } 126 | }; 127 | 128 | template 129 | bool 130 | dispatch(const std::shared_ptr & event) const 131 | { 132 | typedef const typename Extension::template event_dispatcher & dispatcher; 133 | return static_cast(*this)(handler(*this), event); 134 | } 135 | 136 | template 137 | bool 138 | dispatch(const std::shared_ptr & event) const 139 | { 140 | dispatch(event); 141 | return dispatch(event); 142 | } 143 | 144 | template 145 | void 146 | attach(priority p, Sink * s) 147 | { 148 | attach(p, s, opcode()); 149 | } 150 | 151 | template 152 | void 153 | attach(priority p, Sink * s) 154 | { 155 | attach(p, s, opcode()); 156 | attach(p, s); 157 | } 158 | 159 | void attach(priority p, detail::dispatcher * d, uint8_t opcode) 160 | { 161 | m_dispatchers[opcode].emplace(p, d); 162 | } 163 | 164 | template 165 | void 166 | detach(priority p, Sink * s) 167 | { 168 | detach(p, s, opcode()); 169 | } 170 | 171 | template 172 | void 173 | detach(priority p, Sink * s) 174 | { 175 | detach(p, s, opcode()); 176 | detach(p, s); 177 | } 178 | 179 | void 180 | detach(priority p, detail::dispatcher * d, uint8_t opcode) 181 | { 182 | try { 183 | auto & prio_map = m_dispatchers.at(opcode); 184 | const auto & prio_sink_pair = prio_map.equal_range(p); 185 | for (auto it = prio_sink_pair.first; it != prio_sink_pair.second; ) { 186 | if (d == it->second) { 187 | it = prio_map.erase(it); 188 | } else { 189 | ++it; 190 | } 191 | } 192 | } catch (...) {} 193 | } 194 | 195 | }; // xpp::event::source 196 | 197 | }; // namespace event 198 | 199 | }; // namespace xpp 200 | 201 | template 202 | void xpp::event::detail::dispatcher::dispatch(const Event & e) 203 | { 204 | dynamic_cast *>(this)->handle(e); 205 | } 206 | 207 | #endif // XPP_EVENT_HPP 208 | -------------------------------------------------------------------------------- /src/examples/Makefile: -------------------------------------------------------------------------------- 1 | include ../flags.makefile 2 | 3 | CXXFLAGS+=-g 4 | CXXFLAGS+=-Wextra 5 | 6 | CPPSRCS=$(shell find . -name '*.cpp') 7 | EXAMPLES=${CPPSRCS:./%.cpp=%} 8 | 9 | all: ${EXAMPLES} 10 | 11 | clean: 12 | rm -f ${EXAMPLES} 13 | 14 | .PHONY: clean 15 | -------------------------------------------------------------------------------- /src/examples/demo_01.cpp: -------------------------------------------------------------------------------- 1 | // This demo will allow the user to click on a window, grab the keyboard on it 2 | // and then print every key press and release event. Will exit when Escape is 3 | // pressed 4 | 5 | #include 6 | 7 | #include // XKeysymToString 8 | #include // XK_Escape 9 | #include // XC_cross 10 | 11 | #include "../xpp.hpp" 12 | 13 | // global variable to indicate whether the event loop should exit 14 | bool g_quit = false; 15 | 16 | // typedefs for convenience 17 | namespace x { 18 | typedef xpp::connection<> connection; 19 | typedef xpp::event::registry registry; 20 | 21 | typedef xpp::font font; 22 | typedef xpp::cursor cursor; 23 | typedef xpp::window window; 24 | 25 | typedef xpp::x::event::key_press key_press; 26 | typedef xpp::x::event::key_release key_release; 27 | typedef xpp::x::event::button_press button_press; 28 | }; 29 | 30 | // The event handler class 31 | // Implements the xpp::event::sink<..> interface with all events we are 32 | // interested in as template parameters 33 | template 34 | class key_printer 35 | : public xpp::event::sink 36 | { 37 | public: 38 | template 39 | key_printer(C && c) 40 | : m_c(std::forward(c)) 41 | {} 42 | 43 | // xpp::event::sink::handle(...) interface 44 | void handle(const x::key_press & e) 45 | { 46 | auto kbd_mapping = m_c.get_keyboard_mapping(e->detail, 1); 47 | // take the first value from the kbd_mapping list 48 | // This might throw, but for simplicity, no error handling here 49 | auto keysym = *kbd_mapping.keysyms().begin(); 50 | 51 | if (keysym == XK_Escape) { 52 | std::cerr << "quitting" << std::endl; 53 | // parameter has a default value: XCB_TIME_CURRENT_TIME 54 | m_c.ungrab_keyboard(); 55 | g_quit = true; 56 | } else { 57 | std::cerr << "key press: " << XKeysymToString(keysym) << std::endl; 58 | } 59 | } 60 | 61 | // xpp::event::sink::handle(...) interface 62 | void handle(const x::key_release & e) 63 | { 64 | auto kbd_mapping = m_c.get_keyboard_mapping(e->detail, 1); 65 | auto keysym = *kbd_mapping.keysyms().begin(); 66 | std::cerr << "key release: " << XKeysymToString(keysym) << std::endl; 67 | } 68 | 69 | // xpp::event::sink::handle(...) interface 70 | void handle(const x::button_press & e) 71 | { 72 | m_c.ungrab_pointer(XCB_TIME_CURRENT_TIME); 73 | 74 | // event & reply accessors have a default template parameter, the c-type 75 | // Usable with any type which is constructible from the c-type or 76 | // connection + c-type 77 | // xcb_window_t grab_window = e.event(); 78 | x::window grab_window = e.event(); 79 | 80 | if (e->event == e->root) { 81 | // xpp::window, etc. are assignable with the c-type 82 | grab_window = e.child(); 83 | // xpp::window, etc. are implicitly convertible to c-type 84 | auto translate = grab_window.translate_coordinates(grab_window, 1, 1); 85 | grab_window = translate->child; 86 | } 87 | 88 | *m_c.grab_keyboard(true, grab_window, 89 | XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); 90 | 91 | std::cerr << "Grabbed " << grab_window 92 | << ". Press Escape to quit." << std::endl; 93 | } 94 | 95 | private: 96 | Connection m_c; 97 | }; 98 | 99 | int main(int, char **) 100 | { 101 | try { 102 | // xpp::connection is implicitly convertible to xcb_connection_t * 103 | // Hence, it can be used with all xcb_* c functions. 104 | // However, this is not demonstrated here. 105 | x::connection connection; 106 | x::registry registry(connection); 107 | 108 | key_printer key_printer(connection); 109 | registry.attach(0, &key_printer); 110 | 111 | x::font font = x::font::open_checked(connection, "cursor"); 112 | 113 | // x::font, etc. is implicitly convertible to xcb_font_t 114 | x::cursor cursor = x::cursor::create_glyph_checked(connection, font, font, 115 | XC_cross, XC_cross + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff); 116 | 117 | *connection.grab_pointer(false, connection.root(), 118 | XCB_EVENT_MASK_BUTTON_PRESS, 119 | XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, 120 | XCB_NONE, cursor); 121 | // default value for time = XCB_TIME_CURRENT_TIME); 122 | 123 | std::cerr << "Please click on a window" << std::endl; 124 | 125 | while (! g_quit) { 126 | connection.flush(); 127 | registry.dispatch(connection.wait_for_event()); 128 | } 129 | 130 | } catch (const std::exception & error) { 131 | std::cerr << "Exception (std::exception) in " 132 | << __FILE__ << " @ line " << __LINE__ << ", what(): " 133 | << error.what() << std::endl; 134 | std::exit(EXIT_FAILURE); 135 | } 136 | 137 | return EXIT_SUCCESS; 138 | } 139 | -------------------------------------------------------------------------------- /src/examples/demo_02.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../xpp.hpp" 4 | #include "../proto/randr.hpp" 5 | #include "../proto/damage.hpp" 6 | #include "../proto/render.hpp" 7 | 8 | // typedefs for convenience 9 | namespace x { 10 | typedef xpp::connection 13 | connection; 14 | 15 | typedef xpp::event::registry 19 | registry; 20 | 21 | typedef xpp::font font; 22 | typedef xpp::cursor cursor; 23 | typedef xpp::window window; 24 | typedef xpp::window xcb_window; 25 | }; 26 | 27 | int main(int, char **) 28 | { 29 | x::connection connection; 30 | x::registry registry(connection); 31 | 32 | // Print out all available font paths 33 | auto && paths = connection.get_font_path().path(); 34 | std::cerr << "paths " 35 | << "(length: " << std::distance(paths.begin(), paths.end()) << "):" 36 | << std::endl; 37 | for (auto && path : paths) { 38 | std::cerr << "path [" << path.length() << "]: " << path << std::endl; 39 | } 40 | std::cerr << std::endl; 41 | 42 | // Print out all available fonts 43 | auto && fonts = connection.list_fonts(8, 1, "*").names(); 44 | std::cerr << "fonts " 45 | << "(length: " << std::distance(fonts.begin(), fonts.end()) << "):" 46 | << std::endl; 47 | for (auto && name : fonts) { 48 | std::cerr << "font [" << name.length() << "]: " << name << std::endl; 49 | } 50 | std::cerr << std::endl; 51 | 52 | // Print all windows and their subwindows 53 | auto tree = connection.root().query_tree(); 54 | std::cerr << "children: " << std::endl; 55 | for (auto && child : tree.children()) { 56 | std::cerr << child << " "; 57 | auto siblings = child.query_tree().children(); 58 | auto siblings_length = std::distance(siblings.begin(), siblings.end()); 59 | if (siblings_length > 0) { 60 | std::cerr << std::hex << "[" << siblings_length 61 | << " sibling" << (siblings_length > 1 ? "s" : "") << ": "; 62 | for (auto && sibling : siblings) { 63 | std::cerr << "0x" << sibling << (--siblings_length > 0 ? ", " : ""); 64 | } 65 | std::cerr << std::dec << "]" << std::endl; 66 | } else { 67 | std::cerr << "[no siblings]" << std::endl; 68 | } 69 | } 70 | std::cerr << std::endl; 71 | 72 | // Creates an atom called "XPP_STRING_PROPERTY_DEMO" with a string property 73 | // "xpp is working" on the root window 74 | // check with `xprop -root XPP_STRING_PROPERTY_DEMO` 75 | try { 76 | auto my_string_atom = 77 | xpp::x::intern_atom(connection, false, "XPP_STRING_PROPERTY_DEMO"); 78 | 79 | std::string my_string("xpp is working!"); 80 | 81 | std::cerr << "atom for \"XPP_STRING_PROPERTY_DEMO\": " 82 | << my_string_atom.atom() << std::endl; 83 | 84 | auto atom_name = connection.get_atom_name(my_string_atom.atom()); 85 | std::cerr << "atom name: " << atom_name.name() << std::endl;; 86 | 87 | connection.change_property_checked( 88 | XCB_PROP_MODE_REPLACE, connection.root(), 89 | my_string_atom.atom(), XCB_ATOM_STRING, 8, 90 | // using Iterator begin + end here 91 | my_string.begin(), my_string.end()); 92 | 93 | // this will deliberately fail because window = 0 94 | // However, the previous call to change_property succeeded, 95 | // so everything is just fine 96 | connection.change_property_checked( XCB_PROP_MODE_REPLACE, 0, 97 | my_string_atom.atom(), XCB_ATOM_STRING, 8, 98 | // using length() & c_str() 99 | my_string.length(), my_string.c_str()); 100 | 101 | } catch (const std::exception & e) { 102 | std::cerr << "change property failed: " << e.what() << std::endl; 103 | } 104 | std::cerr << std::endl; 105 | 106 | // Get the _NET_CLIENT_LIST_STACKING property 107 | // If an error occurs, it will be thrown only when trying to access the reply 108 | std::string _net_client_list_stacking = "_NET_CLIENT_LIST_STACKING"; 109 | auto net_client_list_stacking_atom = 110 | connection.intern_atom(false, _net_client_list_stacking); 111 | auto net_client_list_stacking = connection.get_property( 112 | false, connection.root(), net_client_list_stacking_atom.atom(), 113 | XCB_ATOM_WINDOW, 0, UINT32_MAX); 114 | 115 | try { 116 | std::cerr << _net_client_list_stacking << " (xcb_window_t):" << std::hex; 117 | for (auto && w : net_client_list_stacking.value()) { 118 | std::cerr << " 0x" << w; 119 | } 120 | std::cerr << std::dec << std::endl; 121 | 122 | std::cerr << _net_client_list_stacking << " (x::window):"; 123 | for (auto && w : net_client_list_stacking.value()) { 124 | std::cerr << " " << w; 125 | } 126 | std::cerr << std::endl; 127 | 128 | std::cerr << _net_client_list_stacking << " (x::xcb_window):"; 129 | for (auto && w : net_client_list_stacking.value()) { 130 | std::cerr << " " << w; 131 | } 132 | std::cerr << std::endl; 133 | 134 | } catch (const std::exception & e) { 135 | std::cerr << "Could not get " << _net_client_list_stacking << " property: " 136 | << e.what() << std::endl; 137 | } 138 | std::cerr << std::endl; 139 | 140 | // Randr needs query_version to work properly in subsequent calls 141 | // If methods are ambiguous (like query_version, then the extension interface 142 | // can be accessed through "extension_name()" (e.g. randr() or damage()) 143 | connection.randr().query_version(XCB_RANDR_MAJOR_VERSION, 144 | XCB_RANDR_MINOR_VERSION); 145 | 146 | connection.select_input_checked(connection.root(), XCB_RANDR_NOTIFY); 147 | 148 | const auto & randr_ext = connection.extension(); 149 | 150 | std::cerr << "RandR Extension" << std::endl; 151 | std::cerr << "\tfirst_event: " << (int)randr_ext->first_event << std::endl; 152 | std::cerr << "\tfirst_error: " << (int)randr_ext->first_error << std::endl; 153 | 154 | const auto & damage_ext = connection.extension(); 155 | 156 | std::cerr << "Damage Extension" << std::endl; 157 | std::cerr << "\tfirst_event: " << (int)damage_ext->first_event << std::endl; 158 | std::cerr << "\tfirst_error: " << (int)damage_ext->first_error << std::endl; 159 | 160 | std::cerr << std::endl; 161 | 162 | try { 163 | // Produces XCB_RANDR_BAD_OUTPUT error 164 | auto output_info = connection.get_output_info(-1); 165 | output_info.get(); 166 | } catch (const std::exception & e) { 167 | std::cerr << "get_output_info error: " << e.what() << std::endl; 168 | } 169 | 170 | try { 171 | // Produces XCB_RANDR_BAD_CRTC error 172 | auto crtc_info = connection.get_crtc_info(-1); 173 | crtc_info.get(); 174 | } catch (const std::exception & e) { 175 | std::cerr << "get_crtc_info error: " << e.what() << std::endl; 176 | } 177 | 178 | // Produces XCB_RANDR_BAD_OUTPUT error in event queue 179 | auto output_info = connection.get_output_info_unchecked(-1); 180 | output_info.get(); 181 | 182 | // Produces XCB_RANDR_BAD_CRTC error in event queue 183 | auto crtc_info = connection.get_crtc_info_unchecked(-1); 184 | crtc_info.get(); 185 | 186 | try { 187 | // XCB_VALUE error 188 | connection.change_output_property_checked(-1, -1, -1, 0, 0, 0, nullptr); 189 | } catch (const std::exception & e) { 190 | std::cerr << "change_output_property error: " << e.what() << std::endl; 191 | } 192 | 193 | // XCB_VALUE error in event queue 194 | connection.change_output_property(-1, -1, -1, 0, 0, 0, nullptr); 195 | 196 | try { 197 | // XCB_RENDER_PICT_FORMAT error 198 | auto pict_index_values = connection.query_pict_index_values(-1); 199 | pict_index_values.get(); 200 | } catch (const std::exception & e) { 201 | std::cerr << "query_pict_index_values error: " << e.what() << std::endl; 202 | } 203 | 204 | try { 205 | // XCB_RENDER_PICTURE error 206 | connection.change_picture_checked(-1, 0, nullptr); 207 | } catch (const std::exception & e) { 208 | std::cerr << "change_picture error: " << e.what() << std::endl; 209 | } 210 | 211 | // XCB_RENDER_PICT_FORMAT error in event queue 212 | auto pict_index_values = connection.query_pict_index_values_unchecked(-1); 213 | pict_index_values.get(); 214 | 215 | // XCB_RENDER_PICTURE error in event queue 216 | connection.change_picture(-1, 0, nullptr); 217 | 218 | // Poll the event queue a couple of times to get the errors 219 | for (int i = 0; i < 5; ++i) { 220 | connection.flush(); 221 | try { 222 | registry.dispatch(connection.wait_for_event()); 223 | } catch (const std::exception & e) { 224 | std::cerr << "std::exception in event queue: " << e.what() << std::endl; 225 | } 226 | } 227 | 228 | return EXIT_SUCCESS; 229 | } 230 | -------------------------------------------------------------------------------- /src/flags.makefile: -------------------------------------------------------------------------------- 1 | LIBS=x11 \ 2 | xcb \ 3 | xcb-icccm \ 4 | xcb-sync \ 5 | xcb-xf86dri \ 6 | xcb-xprint \ 7 | xcb-xinput \ 8 | xcb-shape \ 9 | xcb-shm \ 10 | xcb-render \ 11 | xcb-proto \ 12 | xcb-event \ 13 | xcb-xfixes \ 14 | xcb-xkb \ 15 | xcb-dri3 \ 16 | xcb-ewmh \ 17 | xcb-util \ 18 | xcb-renderutil \ 19 | xcb-xtest \ 20 | xcb-xevie \ 21 | xcb-keysyms \ 22 | xcb-image \ 23 | xcb-composite \ 24 | xcb-randr \ 25 | xcb-present \ 26 | xcb-xv \ 27 | xcb-aux \ 28 | xcb-record \ 29 | xcb-dpms \ 30 | xcb-glx \ 31 | xcb-atom \ 32 | xcb-damage \ 33 | xcb-screensaver \ 34 | xcb-xvmc \ 35 | xcb-res \ 36 | xcb-xinerama \ 37 | xcb-dri2 38 | 39 | CXXFLAGS=-std=c++11 -Wall -O0 $(shell pkg-config --cflags ${LIBS}) 40 | LDFLAGS=$(shell pkg-config --libs ${LIBS}) 41 | -------------------------------------------------------------------------------- /src/font.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_FONT_HPP 2 | #define XPP_FONT_HPP 3 | 4 | #include "proto/x.hpp" 5 | #include "generic/resource.hpp" 6 | 7 | namespace xpp { 8 | 9 | template class ... Interfaces> 10 | class font 11 | : public xpp::generic::resource 13 | { 14 | protected: 15 | using base = xpp::generic::resource; 17 | 18 | template 19 | font(C && c, Create && create, Destroy && destroy) 20 | : base(base::make(std::forward(c), 21 | std::forward(create), 22 | std::forward(destroy))) 23 | {} 24 | 25 | public: 26 | using base::base; 27 | using base::operator=; 28 | 29 | template 30 | static 31 | font 32 | open(C && c, const std::string & name) noexcept 33 | { 34 | return font(std::forward(c), 35 | [&](const Connection & c, const xcb_font_t & font) 36 | { 37 | xpp::x::open_font(c, font, name); 38 | }, 39 | [&](const Connection & c, const xcb_font_t & font) 40 | { 41 | xpp::x::close_font(c, font); 42 | }); 43 | } 44 | 45 | template 46 | static 47 | font 48 | open_checked(C && c, const std::string & name) 49 | { 50 | return font(std::forward(c), 51 | [&](const Connection & c, const xcb_font_t & font) 52 | { 53 | xpp::x::open_font_checked(c, font, name); 54 | }, 55 | [&](const Connection & c, const xcb_font_t & font) 56 | { 57 | xpp::x::close_font_checked(c, font); 58 | }); 59 | } 60 | }; 61 | 62 | namespace generic { 63 | 64 | template class ... Interfaces> 65 | struct traits> 66 | { 67 | typedef xcb_font_t type; 68 | }; 69 | 70 | }; // namespace generic 71 | 72 | }; // namespace xpp 73 | 74 | #endif // XPP_FONT_HPP 75 | -------------------------------------------------------------------------------- /src/fontable.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_FONTABLE_HPP 2 | #define XPP_FONTABLE_HPP 3 | 4 | #include "proto/x.hpp" 5 | #include "generic/resource.hpp" 6 | 7 | namespace xpp { 8 | 9 | template class ... Interfaces> 10 | class fontable 11 | : public xpp::generic::resource 13 | { 14 | protected: 15 | using base = xpp::generic::resource; 17 | 18 | public: 19 | using base::base; 20 | using base::operator=; 21 | }; 22 | 23 | namespace generic { 24 | 25 | template class ... Interfaces> 26 | struct traits> 27 | { 28 | typedef xcb_fontable_t type; 29 | }; 30 | 31 | }; // namespace generic 32 | 33 | }; // namespace xpp 34 | 35 | #endif // XPP_FONTABLE_HPP 36 | -------------------------------------------------------------------------------- /src/gcontext.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GCONTEXT_HPP 2 | #define XPP_GCONTEXT_HPP 3 | 4 | #include "proto/x.hpp" 5 | #include "generic/resource.hpp" 6 | 7 | namespace xpp { 8 | 9 | template class ... Interfaces> 10 | class gcontext 11 | : public xpp::generic::resource 13 | { 14 | protected: 15 | using base = xpp::generic::resource; 17 | 18 | template 19 | gcontext(C && c, Create && create, Destroy && destroy) 20 | : base(base::make(std::forward(c), 21 | std::forward(create), 22 | std::forward(destroy))) 23 | {} 24 | 25 | public: 26 | using base::base; 27 | using base::operator=; 28 | 29 | template 30 | static 31 | gcontext 32 | create(C && c, xcb_drawable_t drawable, 33 | uint32_t value_mask, const uint32_t * value_list) 34 | { 35 | return gcontext( 36 | std::forward(c), 37 | [&](const Connection & c, const xcb_gcontext_t & gcontext) 38 | { 39 | xpp::x::create_gc(c, gcontext, drawable, value_mask, value_list); 40 | }, 41 | [&](const Connection & c, const xcb_gcontext_t & gcontext) 42 | { 43 | xpp::x::free_gc(c, gcontext); 44 | }); 45 | } 46 | 47 | template 48 | static 49 | gcontext 50 | create_checked(C && c, xcb_drawable_t drawable, 51 | uint32_t value_mask, const uint32_t * value_list) 52 | { 53 | return gcontext( 54 | std::forward(c), 55 | [&](const Connection & c, const xcb_gcontext_t & gcontext) 56 | { 57 | xpp::x::create_gc_checked(c, gcontext, drawable, 58 | value_mask, value_list); 59 | }, 60 | [&](const Connection & c, const xcb_gcontext_t & gcontext) 61 | { 62 | xpp::x::free_gc_checked(c, gcontext); 63 | }); 64 | } 65 | 66 | template 67 | static 68 | gcontext 69 | copy(C && c, xcb_gcontext_t src_gc, uint32_t value_mask) 70 | { 71 | return gcontext( 72 | std::forward(c), 73 | [&](const Connection & c, const xcb_gcontext_t & gcontext) 74 | { 75 | xpp::x::copy_gc(c, src_gc, gcontext, value_mask); 76 | }, 77 | [&](const Connection & c, const xcb_gcontext_t & gcontext) 78 | { 79 | xpp::x::free_gc(c, gcontext); 80 | }); 81 | } 82 | 83 | 84 | template 85 | static 86 | gcontext 87 | copy_checked(C && c, xcb_gcontext_t src_gc, uint32_t value_mask) 88 | { 89 | return gcontext( 90 | std::forward(c), 91 | [&](const Connection & c, const xcb_gcontext_t & gcontext) 92 | { 93 | xpp::x::copy_gc_checked(c, src_gc, gcontext, value_mask); 94 | }, 95 | [&](const Connection & c, const xcb_gcontext_t & gcontext) 96 | { 97 | xpp::x::free_gc_checked(c, gcontext); 98 | }); 99 | } 100 | }; 101 | 102 | namespace generic { 103 | 104 | template class ... Interfaces> 105 | struct traits> 106 | { 107 | typedef xcb_gcontext_t type; 108 | }; 109 | 110 | }; // namespace generic 111 | 112 | }; // namespace xpp 113 | 114 | #endif // XPP_GCONTEXT_HPP 115 | -------------------------------------------------------------------------------- /src/generic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GENERIC_HPP 2 | #define XPP_GENERIC_HPP 3 | 4 | #include "generic/error.hpp" 5 | #include "generic/event.hpp" 6 | #include "generic/factory.hpp" 7 | #include "generic/request.hpp" 8 | #include "generic/resource.hpp" 9 | #include "generic/extension.hpp" 10 | #include "generic/signature.hpp" 11 | #include "generic/reply_iterator.hpp" 12 | #include "generic/iterator_traits.hpp" 13 | #include "generic/input_iterator_adapter.hpp" 14 | 15 | #endif // XPP_GENERIC_HPP 16 | -------------------------------------------------------------------------------- /src/generic/error.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GENERIC_ERROR_HPP 2 | #define XPP_GENERIC_ERROR_HPP 3 | 4 | #include // shared_ptr 5 | #include // shared_ptr 6 | #include // xcb_generic_error_t 7 | 8 | namespace xpp { namespace generic { 9 | 10 | class error_dispatcher { 11 | public: 12 | virtual 13 | void operator()(const std::shared_ptr &) const = 0; 14 | }; 15 | 16 | namespace detail { 17 | 18 | template 19 | void 20 | dispatch(const Object & object, 21 | const std::shared_ptr & error, 22 | std::true_type) 23 | { 24 | static_cast(object)(error); 25 | } 26 | 27 | template 28 | void 29 | dispatch(const Object &, 30 | const std::shared_ptr & error, 31 | std::false_type) 32 | { 33 | throw error; 34 | } 35 | 36 | }; // namespace detail 37 | 38 | template 39 | void 40 | dispatch(const Object & object, 41 | const std::shared_ptr & error) 42 | { 43 | detail::dispatch(object, 44 | error, 45 | std::is_base_of()); 46 | } 47 | 48 | template 49 | class error 50 | : public std::runtime_error 51 | { 52 | public: 53 | error(const std::shared_ptr & error) 54 | : runtime_error(get_error_description(error.get())) 55 | , m_error(error) 56 | {} 57 | 58 | virtual 59 | ~error(void) 60 | {} 61 | 62 | virtual 63 | operator const Error &(void) const 64 | { 65 | return reinterpret_cast(*m_error); 66 | } 67 | 68 | virtual 69 | const Error & 70 | operator*(void) const 71 | { 72 | return reinterpret_cast(*m_error); 73 | } 74 | 75 | virtual 76 | Error * 77 | operator->(void) const 78 | { 79 | return reinterpret_cast(m_error.get()); 80 | } 81 | 82 | protected: 83 | virtual 84 | std::string 85 | get_error_description(xcb_generic_error_t * error) const 86 | { 87 | return std::string(Derived::description()) 88 | + " (" + std::to_string(error->error_code) + ")"; 89 | } 90 | 91 | std::shared_ptr m_error; 92 | }; // class error 93 | 94 | }; }; // xpp::generic 95 | 96 | #endif // XPP_GENERIC_ERROR_HPP 97 | -------------------------------------------------------------------------------- /src/generic/event.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GENERIC_EVENT_HPP 2 | #define XPP_GENERIC_EVENT_HPP 3 | 4 | #include // shared_ptr 5 | #include // xcb_generic_event_t 6 | 7 | namespace xpp { namespace generic { 8 | 9 | template 10 | class event { 11 | public: 12 | event(const std::shared_ptr & event) 13 | : m_event(event) 14 | {} 15 | 16 | virtual 17 | ~event(void) {} 18 | 19 | virtual 20 | operator const Event &(void) const 21 | { 22 | return reinterpret_cast(*m_event); 23 | } 24 | 25 | virtual 26 | const Event & 27 | operator*(void) const 28 | { 29 | return reinterpret_cast(*m_event); 30 | } 31 | 32 | virtual 33 | Event * 34 | operator->(void) const 35 | { 36 | return reinterpret_cast(m_event.get()); 37 | } 38 | 39 | protected: 40 | std::shared_ptr m_event; 41 | }; // class event 42 | 43 | }; }; // namespace xpp::generic 44 | 45 | #endif // XPP_GENERIC_EVENT_HPP 46 | -------------------------------------------------------------------------------- /src/generic/extension.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GENERIC_EXTENSION_HPP 2 | #define XPP_GENERIC_EXTENSION_HPP 3 | 4 | // #include 5 | #include 6 | 7 | namespace xpp { namespace generic { 8 | 9 | template 10 | class extension 11 | { 12 | public: 13 | extension(xcb_connection_t * const c) 14 | : m_c(c) 15 | { 16 | prefetch(); 17 | } 18 | 19 | const xcb_query_extension_reply_t & 20 | operator*(void) const 21 | { 22 | return *m_extension; 23 | } 24 | 25 | const xcb_query_extension_reply_t * 26 | operator->(void) const 27 | { 28 | return m_extension; 29 | } 30 | 31 | operator const xcb_query_extension_reply_t *(void) const 32 | { 33 | return m_extension; 34 | } 35 | 36 | Derived & 37 | get(void) 38 | { 39 | m_extension = xcb_get_extension_data(m_c, Id); 40 | return static_cast(*this); 41 | } 42 | 43 | Derived & 44 | prefetch(void) 45 | { 46 | xcb_prefetch_extension_data(m_c, Id); 47 | return static_cast(*this); 48 | } 49 | 50 | private: 51 | xcb_connection_t * m_c = nullptr; 52 | // The result must not be freed. 53 | // This storage is managed by the cache itself. 54 | const xcb_query_extension_reply_t * m_extension = nullptr; 55 | }; // class extension 56 | 57 | }; }; // namespace xpp::generic 58 | 59 | #endif // XPP_GENERIC_EXTENSION_HPP 60 | -------------------------------------------------------------------------------- /src/generic/factory.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GENERIC_FACTORY_HPP 2 | #define XPP_GENERIC_FACTORY_HPP 3 | 4 | #include // std::forward 5 | 6 | namespace xpp { namespace generic { 7 | 8 | namespace factory { 9 | 10 | template 11 | class make_object 12 | { 13 | public: 14 | template 15 | ReturnType 16 | operator()(Connection &&, Parameter && ... parameter) const 17 | { 18 | return ReturnType { std::forward(parameter) ... }; 19 | } 20 | }; 21 | 22 | template 23 | class make_object_with_member 24 | { 25 | public: 26 | template 27 | ReturnType 28 | operator()(Connection && c, Member && member, Parameter && ... parameter) const 29 | { 30 | return ReturnType { std::forward(member) 31 | , std::forward(c) 32 | , std::forward(parameter) ... 33 | }; 34 | } 35 | }; 36 | 37 | template 38 | class make_object_with_connection 39 | { 40 | public: 41 | template 42 | ReturnType 43 | operator()(Connection && c, Parameter && ... parameter) const 44 | { 45 | return ReturnType { std::forward(c) 46 | , std::forward(parameter) ... 47 | }; 48 | } 49 | }; 50 | 51 | template 52 | class make_fundamental { 53 | public: 54 | template 55 | ReturnType 56 | operator()(Connection &&, Member && member) const 57 | { 58 | return std::forward(member); 59 | } 60 | }; 61 | 62 | template 66 | class make 67 | : public std::conditional< 68 | std::is_constructible::value, 69 | make_fundamental, 70 | typename std::conditional< 71 | std::is_constructible::value, 75 | make_object_with_member, 76 | typename std::conditional< 77 | std::is_constructible::value, 81 | make_object_with_connection, 82 | make_object 83 | >::type 84 | >::type 85 | >::type 86 | {}; 87 | 88 | }; // namespace factory 89 | 90 | }; }; // xpp::generic 91 | 92 | #endif // XPP_GENERIC_FACTORY_HPP 93 | -------------------------------------------------------------------------------- /src/generic/input_iterator_adapter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GENERIC_INPUT_ITERATOR_ADAPTER_HPP 2 | #define XPP_GENERIC_INPUT_ITERATOR_ADAPTER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define GENERATE_HAS_MEMBER(member) \ 9 | \ 10 | template \ 11 | class HasMember_##member { \ 12 | private: \ 13 | using Yes = char[2]; \ 14 | using No = char[1]; \ 15 | \ 16 | struct Fallback { int member; }; \ 17 | struct Derived : T, Fallback {}; \ 18 | \ 19 | template \ 20 | static No& test(decltype(U::member)*); \ 21 | template \ 22 | static Yes& test(U*); \ 23 | \ 24 | public: \ 25 | static constexpr bool RESULT = sizeof(test(nullptr)) == sizeof(Yes); \ 26 | }; \ 27 | \ 28 | template \ 29 | class HasMember_##member { \ 30 | public: \ 31 | static constexpr bool RESULT = false; \ 32 | }; \ 33 | \ 34 | template \ 35 | struct has_member_##member \ 36 | : public std::integral_constant< \ 37 | bool, \ 38 | HasMember_##member::value>::RESULT \ 39 | > \ 40 | {}; 41 | 42 | GENERATE_HAS_MEMBER(first) 43 | GENERATE_HAS_MEMBER(second) 44 | 45 | // namespace iterator { 46 | 47 | template 48 | struct value_iterator_base { 49 | value_iterator_base(const Iterator & iterator) 50 | : m_iterator(iterator) 51 | {} 52 | 53 | bool 54 | operator==(const value_iterator_base & other) 55 | { 56 | return m_iterator == other.m_iterator; 57 | } 58 | 59 | bool 60 | operator!=(const value_iterator_base & other) 61 | { 62 | return m_iterator != other.m_iterator; 63 | } 64 | 65 | void 66 | operator++(void) 67 | { 68 | ++m_iterator; 69 | } 70 | 71 | template 72 | const Value & 73 | get_value(const std::pair & pair) 74 | { 75 | return pair.second; 76 | } 77 | 78 | template 79 | const Value & 80 | get_value(const Value & v) 81 | { 82 | return v; 83 | } 84 | 85 | Iterator m_iterator; 86 | }; 87 | 88 | template 89 | struct value_iterator_pair 90 | : public value_iterator_base 91 | , public std::iterator::difference_type, 95 | // pointer 96 | typename Iterator::value_type::second_type *, 97 | // reference 98 | const typename Iterator::value_type::second_type &> 99 | { 100 | typedef value_iterator_base base; 101 | using base::base; 102 | 103 | const typename Iterator::value_type::second_type & 104 | operator*(void) 105 | { 106 | return base::get_value(*base::m_iterator); 107 | } 108 | }; 109 | 110 | template 111 | struct value_iterator_integral 112 | : public value_iterator_base 113 | , public std::iterator::value_type, 115 | typename std::iterator_traits::difference_type, 116 | typename std::iterator_traits::pointer, 117 | typename std::iterator_traits::reference> 118 | { 119 | typedef value_iterator_base base; 120 | using base::base; 121 | 122 | const typename Iterator::value_type & 123 | operator*(void) 124 | { 125 | return base::get_value(*base::m_iterator); 126 | } 127 | }; 128 | 129 | template 130 | struct value_iterator 131 | : public std::conditional< 132 | has_member_first::value 133 | && has_member_second::value, 134 | value_iterator_pair, 135 | value_iterator_integral 136 | >::type 137 | { 138 | typedef typename std::conditional< 139 | has_member_first::value 140 | && has_member_second::value, 141 | value_iterator_pair, 142 | value_iterator_integral 143 | >::type base; 144 | using base::base; 145 | }; 146 | 147 | template 148 | struct value_type { 149 | typedef typename std::conditional< 150 | has_member_second::value, 151 | typename T::value_type::second_type, 152 | typename T::value_type>::type 153 | type; 154 | }; 155 | 156 | template 157 | struct value_type { 158 | typedef typename std::remove_const< 159 | typename std::remove_pointer::type 160 | >::type type; 161 | }; 162 | 163 | #endif // XPP_GENERIC_INPUT_ITERATOR_ADAPTER_HPP 164 | -------------------------------------------------------------------------------- /src/generic/iterator_traits.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GENERIC_ITERATOR_TRAITS_HPP 2 | #define XPP_GENERIC_ITERATOR_TRAITS_HPP 3 | 4 | namespace xpp { 5 | 6 | namespace generic { 7 | 8 | template 9 | struct traits 10 | { 11 | typedef T type; 12 | }; 13 | 14 | template 15 | struct conversion_type 16 | { 17 | using type = typename traits::type; 18 | }; 19 | 20 | }; // namespace generic 21 | 22 | }; 23 | 24 | #endif // XPP_GENERIC_ITERATOR_TRAITS_HPP 25 | -------------------------------------------------------------------------------- /src/generic/reply_iterator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GENERIC_REPLY_ITERATOR_HPP 2 | #define XPP_GENERIC_REPLY_ITERATOR_HPP 3 | 4 | #include // size_t 5 | #include 6 | #include 7 | #include // xcb_str_* 8 | #include "factory.hpp" 9 | #include "signature.hpp" 10 | #include "iterator_traits.hpp" 11 | 12 | #define NEXT_TEMPLATE \ 13 | void (&Next)(XcbIterator *) 14 | 15 | #define NEXT_SIGNATURE \ 16 | xpp::generic::signature 17 | 18 | #define SIZEOF_TEMPLATE \ 19 | int (&SizeOf)(const void *) 20 | 21 | #define SIZEOF_SIGNATURE \ 22 | xpp::generic::signature 23 | 24 | #define GETITERATOR_TEMPLATE \ 25 | XcbIterator (&GetIterator)(const Reply *) 26 | 27 | #define GETITERATOR_SIGNATURE \ 28 | xpp::generic::signature 29 | 30 | #define ACCESSOR_TEMPLATE \ 31 | Data * (&Accessor)(const Reply *) 32 | 33 | #define ACCESSOR_SIGNATURE \ 34 | xpp::generic::signature 35 | 36 | #define LENGTH_TEMPLATE \ 37 | int (&Length)(const Reply *) 38 | 39 | #define LENGTH_SIGNATURE \ 40 | xpp::generic::signature 41 | 42 | namespace xpp { 43 | 44 | namespace generic { 45 | 46 | // iterator for variable size data fields 47 | 48 | template 49 | class iterator; 50 | 51 | template 58 | class iterator 63 | : public std::iterator 68 | { 69 | protected: 70 | using self = iterator; 75 | 76 | // typename Dummy to allow specialization in class scope 77 | template 78 | class get 79 | { 80 | public: 81 | Data 82 | operator()(Data * const data) 83 | { 84 | return *data; 85 | } 86 | }; 87 | 88 | template 89 | class get 90 | { 91 | public: 92 | std::string 93 | operator()(xcb_str_t * const data) 94 | { 95 | return std::string(xcb_str_name(data), 96 | xcb_str_name_length(data)); 97 | } 98 | }; 99 | 100 | Connection m_c; 101 | std::shared_ptr m_reply; 102 | std::stack m_lengths; 103 | XcbIterator m_iterator; 104 | 105 | public: 106 | iterator(void) {} 107 | 108 | template 109 | iterator(C && c, const std::shared_ptr & reply) 110 | : m_c(std::forward(c)) 111 | , m_reply(reply) 112 | , m_iterator(GetIterator(reply.get())) 113 | {} 114 | 115 | bool 116 | operator==(const iterator & other) 117 | { 118 | return m_iterator.rem == other.m_iterator.rem; 119 | } 120 | 121 | bool 122 | operator!=(const iterator & other) 123 | { 124 | return ! (*this == other); 125 | } 126 | 127 | auto 128 | operator*(void) -> decltype(get()(this->m_iterator.data)) 129 | { 130 | return get()(m_iterator.data); 131 | } 132 | 133 | // prefix 134 | self & 135 | operator++(void) 136 | { 137 | m_lengths.push(SizeOf(m_iterator.data)); 138 | Next(&m_iterator); 139 | return *this; 140 | } 141 | 142 | // postfix 143 | self 144 | operator++(int) 145 | { 146 | auto copy = *this; 147 | ++(*this); 148 | return copy; 149 | } 150 | 151 | // prefix 152 | self & 153 | operator--(void) 154 | { 155 | typedef typename std::remove_pointer::type data_t; 156 | if (m_lengths.empty()) { 157 | data_t * data = m_iterator.data; 158 | data_t * prev = data - m_lengths.top(); 159 | m_lengths.pop(); 160 | m_iterator.index = (char *)m_iterator.data - (char *)prev; 161 | m_iterator.data = prev; 162 | ++m_iterator.rem; 163 | } 164 | return *this; 165 | } 166 | 167 | // postfix 168 | self 169 | operator--(int) 170 | { 171 | auto copy = *this; 172 | --(*this); 173 | return copy; 174 | } 175 | 176 | template 177 | static 178 | self 179 | begin(C && c, const std::shared_ptr & reply) 180 | { 181 | return self { std::forward(c), reply }; 182 | } 183 | 184 | template 185 | static 186 | self 187 | end(C && c, const std::shared_ptr & reply) 188 | { 189 | auto it = self { std::forward(c), reply }; 190 | it.m_iterator.rem = 0; 191 | return it; 192 | } 193 | }; // class iterator 194 | 195 | // iterator for fixed size data fields 196 | 197 | template 203 | class iterator 207 | : public std::iterator 212 | { 213 | protected: 214 | using data_t = typename std::conditional::value, 215 | typename xpp::generic::conversion_type::type, Data>::type; 216 | using make = xpp::generic::factory::make; 217 | 218 | Connection m_c; 219 | std::size_t m_index = 0; 220 | std::shared_ptr m_reply; 221 | 222 | public: 223 | typedef iterator 227 | self; 228 | 229 | iterator(void) {} 230 | 231 | template 232 | iterator(C && c, 233 | const std::shared_ptr & reply, 234 | std::size_t index) 235 | : m_c(c) 236 | , m_index(index) 237 | , m_reply(reply) 238 | { 239 | if (std::is_void::value) { 240 | m_index /= sizeof(data_t); 241 | } 242 | } 243 | 244 | bool operator==(const iterator & other) 245 | { 246 | return m_index == other.m_index; 247 | } 248 | 249 | bool operator!=(const iterator & other) 250 | { 251 | return ! (*this == other); 252 | } 253 | 254 | Object operator*(void) 255 | { 256 | return make()(m_c, static_cast(Accessor(m_reply.get()))[m_index]); 257 | } 258 | 259 | // prefix 260 | self & operator++(void) 261 | { 262 | ++m_index; 263 | return *this; 264 | } 265 | 266 | // postfix 267 | self operator++(int) 268 | { 269 | auto copy = *this; 270 | ++(*this); 271 | return copy; 272 | } 273 | 274 | // prefix 275 | self & operator--(void) 276 | { 277 | --m_index; 278 | return *this; 279 | } 280 | 281 | // postfix 282 | self operator--(int) 283 | { 284 | auto copy = *this; 285 | --(*this); 286 | return copy; 287 | } 288 | 289 | template 290 | static 291 | self 292 | begin(C && c, const std::shared_ptr & reply) 293 | { 294 | return self { std::forward(c), reply, 0 }; 295 | } 296 | 297 | template 298 | static 299 | self 300 | end(C && c, const std::shared_ptr & reply) 301 | { 302 | return self { std::forward(c), 303 | reply, 304 | static_cast(Length(reply.get())) }; 305 | } 306 | }; // class iterator 307 | 308 | template 309 | class list { 310 | private: 311 | // before public part, to make decltype in begin() & end() work! 312 | Connection m_c; 313 | std::shared_ptr m_reply; 314 | 315 | public: 316 | template 317 | list(C && c, const std::shared_ptr & reply) 318 | : m_c(std::forward(c)), m_reply(reply) 319 | {} 320 | 321 | auto 322 | begin(void) -> decltype(Iterator::begin(this->m_c, this->m_reply)) 323 | { 324 | return Iterator::begin(m_c, m_reply); 325 | } 326 | 327 | auto 328 | end(void) -> decltype(Iterator::end(this->m_c, this->m_reply)) 329 | { 330 | return Iterator::end(m_c, m_reply); 331 | } 332 | }; // class list 333 | 334 | }; // namespace generic 335 | 336 | }; // namespace xpp 337 | 338 | #endif // XPP_GENERIC_REPLY_ITERATOR_HPP 339 | -------------------------------------------------------------------------------- /src/generic/request.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GENERIC_REQUEST_HPP 2 | #define XPP_GENERIC_REQUEST_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "error.hpp" 9 | #include "signature.hpp" 10 | 11 | #define REPLY_TEMPLATE \ 12 | typename Reply, \ 13 | typename Cookie, \ 14 | Reply *(&ReplyFunction)(xcb_connection_t *, Cookie, xcb_generic_error_t **) 15 | 16 | #define REPLY_SIGNATURE \ 17 | xpp::generic::signature 21 | 22 | #define REPLY_COOKIE_TEMPLATE \ 23 | typename ... CookieParameter, \ 24 | Cookie(&CookieFunction)(CookieParameter ...) 25 | 26 | #define REPLY_COOKIE_SIGNATURE \ 27 | xpp::generic::signature 28 | 29 | namespace xpp { namespace generic { 30 | 31 | template 32 | void 33 | check(Connection && c, const xcb_void_cookie_t & cookie) 34 | { 35 | xcb_generic_error_t * error = 36 | xcb_request_check(std::forward(c), cookie); 37 | if (error) { 38 | dispatch(std::forward(c), 39 | std::shared_ptr(error, std::free)); 40 | } 41 | } 42 | 43 | struct checked_tag {}; 44 | struct unchecked_tag {}; 45 | 46 | template 47 | class reply; 48 | 49 | template 54 | class reply 59 | { 60 | public: 61 | template 62 | reply(C && c, Parameter && ... parameter) 63 | : m_c(std::forward(c)) 64 | , m_cookie(Derived::cookie(std::forward(c), 65 | std::forward(parameter) ...)) 66 | {} 67 | 68 | operator bool(void) 69 | { 70 | return m_reply.operator bool(); 71 | } 72 | 73 | const Reply & 74 | operator*(void) 75 | { 76 | return *get(); 77 | } 78 | 79 | Reply * 80 | operator->(void) 81 | { 82 | return get().get(); 83 | } 84 | 85 | const std::shared_ptr & 86 | get(void) 87 | { 88 | if (! m_reply) { 89 | m_reply = get(Check()); 90 | } 91 | return m_reply; 92 | } 93 | 94 | template 95 | static 96 | Cookie 97 | cookie(Parameter && ... parameter) 98 | { 99 | return CookieFunction(std::forward(parameter) ...); 100 | } 101 | 102 | protected: 103 | Connection m_c; 104 | Cookie m_cookie; 105 | std::shared_ptr m_reply; 106 | 107 | std::shared_ptr 108 | get(checked_tag) 109 | { 110 | xcb_generic_error_t * error = nullptr; 111 | auto reply = std::shared_ptr(ReplyFunction(m_c, m_cookie, &error), 112 | std::free); 113 | if (error) { 114 | dispatch(m_c, std::shared_ptr(error, std::free)); 115 | } 116 | return reply; 117 | } 118 | 119 | std::shared_ptr 120 | get(unchecked_tag) 121 | { 122 | return std::shared_ptr(ReplyFunction(m_c, m_cookie, nullptr), 123 | std::free); 124 | } 125 | }; 126 | 127 | }; }; // namespace xpp::generic 128 | 129 | #endif // XPP_GENERIC_REQUEST_HPP 130 | -------------------------------------------------------------------------------- /src/generic/resource.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GENERIC_RESOURCE_HPP 2 | #define XPP_GENERIC_RESOURCE_HPP 3 | 4 | #include // std::{hex,dec} 5 | #include // std::shared_ptr 6 | #include "iterator_traits.hpp" 7 | 8 | #include // xcb_generate_id 9 | 10 | namespace xpp { 11 | 12 | namespace generic { 13 | 14 | namespace detail { 15 | 16 | template class ... Interfaces> 18 | class interfaces 19 | : public Interfaces, 20 | Connection> ... 21 | { 22 | public: 23 | const ResourceId & 24 | resource(void) const 25 | { 26 | return *static_cast(*this); 27 | } 28 | 29 | Connection 30 | connection(void) const 31 | { 32 | return static_cast(*this).connection(); 33 | } 34 | }; // class interfaces 35 | 36 | }; 37 | 38 | template class ... Interfaces> 40 | class resource 41 | : public detail::interfaces, 43 | ResourceId, Interfaces ...> 44 | { 45 | protected: 46 | using self = resource; 47 | 48 | Connection m_c; 49 | // reference counting for Resource object 50 | std::shared_ptr m_resource; 51 | 52 | resource(Connection c) 53 | : m_c(c) 54 | {} 55 | 56 | template 57 | static 58 | self 59 | make(C && c, Create create, Destroy destroy) 60 | { 61 | self resource(std::forward(c)); 62 | 63 | auto xid = xcb_generate_id(std::forward(c)); 64 | 65 | // class create before instatiating the shared_ptr 66 | // create might fail and throw an error, hence shared_ptr would hold an 67 | // invalid xid, causing possibly another exception in destroy() 68 | // when create() throws, then the shared_ptr will not be created 69 | create(std::forward(c), xid); 70 | 71 | resource.m_resource = 72 | std::shared_ptr(new ResourceId(xid), 73 | [&](ResourceId * r) 74 | { 75 | destroy(resource.m_c, *r); 76 | delete r; 77 | }); 78 | 79 | return resource; 80 | } 81 | 82 | public: 83 | template 84 | resource(C && c, const ResourceId & resource_id) 85 | : m_c(std::forward(c)) 86 | , m_resource(std::make_shared(resource_id)) 87 | {} 88 | 89 | resource(const resource & other) 90 | : m_c(other.m_c) 91 | , m_resource(other.m_resource) 92 | {} 93 | 94 | virtual 95 | void 96 | operator=(const resource & other) 97 | { 98 | m_c = other.m_c; 99 | m_resource = other.m_resource; 100 | } 101 | 102 | virtual 103 | void 104 | operator=(const ResourceId & resource) 105 | { 106 | m_resource = std::make_shared(resource); 107 | } 108 | 109 | virtual 110 | const ResourceId & 111 | operator*(void) const 112 | { 113 | return *m_resource; 114 | } 115 | 116 | virtual 117 | operator const ResourceId &(void) const 118 | { 119 | return *m_resource; 120 | } 121 | 122 | Connection 123 | connection(void) const 124 | { 125 | return m_c; 126 | } 127 | }; // class resource 128 | 129 | template class ... Interfaces> 131 | std::ostream & 132 | operator<<(std::ostream & os, 133 | const resource & resource) 134 | { 135 | return os << std::hex << "0x" << *resource << std::dec; 136 | } 137 | 138 | }; // namespace generic 139 | 140 | }; // namespace xpp 141 | 142 | #endif // XPP_GENERIC_RESOURCE_HPP 143 | -------------------------------------------------------------------------------- /src/generic/signature.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_GENERIC_SIGNATURE_HPP 2 | #define XPP_GENERIC_SIGNATURE_HPP 3 | 4 | #define SIGNATURE(NAME) \ 5 | xpp::generic::signature 6 | 7 | namespace xpp { namespace generic { 8 | 9 | template 10 | class signature; 11 | 12 | }; }; 13 | 14 | #endif // XPP_GENERIC_SIGNATURE_HPP 15 | -------------------------------------------------------------------------------- /src/pixmap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_PIXMAP_HPP 2 | #define XPP_PIXMAP_HPP 3 | 4 | #include "proto/x.hpp" 5 | #include "generic/resource.hpp" 6 | 7 | namespace xpp { 8 | 9 | template class ... Interfaces> 10 | class pixmap 11 | : public xpp::generic::resource 13 | { 14 | protected: 15 | using base = xpp::generic::resource; 17 | 18 | template 19 | pixmap(C && c, Create && create, Destroy && destroy) 20 | : base(base::make(std::forward(c), 21 | std::forward(create), 22 | std::forward(destroy))) 23 | {} 24 | 25 | public: 26 | using base::base; 27 | using base::operator=; 28 | 29 | template 30 | static 31 | pixmap 32 | create(C && c, uint8_t depth, xcb_drawable_t drawable, 33 | uint16_t width, uint16_t height) 34 | { 35 | return pixmap( 36 | std::forward(c), 37 | [&](const Connection & c, const xcb_pixmap_t & pixmap) 38 | { 39 | xpp::x::create_pixmap(c, depth, pixmap, drawable, width, height); 40 | }, 41 | [&](const Connection & c, const xcb_pixmap_t & pixmap) 42 | { 43 | xpp::x::free_pixmap(c, pixmap); 44 | }); 45 | } 46 | 47 | template 48 | static 49 | pixmap 50 | create_checked(C && c, uint8_t depth, xcb_drawable_t drawable, 51 | uint16_t width, uint16_t height) 52 | { 53 | return pixmap( 54 | std::forward(c), 55 | [&](const Connection & c, const xcb_pixmap_t & pixmap) 56 | { 57 | xpp::x::create_pixmap_checked(c, depth, pixmap, drawable, width, height); 58 | }, 59 | [&](const Connection & c, const xcb_pixmap_t & pixmap) 60 | { 61 | xpp::x::free_pixmap_checked(c, pixmap); 62 | }); 63 | } 64 | }; 65 | 66 | namespace generic { 67 | 68 | template class ... Interfaces> 69 | struct traits> 70 | { 71 | typedef xcb_pixmap_t type; 72 | }; 73 | 74 | }; // namespace generic 75 | 76 | }; // namespace xpp 77 | 78 | #endif // XPP_PIXMAP_HPP 79 | -------------------------------------------------------------------------------- /src/proto/Makefile: -------------------------------------------------------------------------------- 1 | include ../flags.makefile 2 | 3 | # find ${PROTODIR} -iname '*.xml' -exec basename {} .xml \; 4 | # without ge, xf86vidmode 5 | PROTOS= \ 6 | present \ 7 | dpms \ 8 | shm \ 9 | damage \ 10 | dri3 \ 11 | render \ 12 | xfixes \ 13 | screensaver \ 14 | bigreq \ 15 | xprint \ 16 | xinerama \ 17 | xkb \ 18 | xc_misc \ 19 | record \ 20 | xproto \ 21 | xvmc \ 22 | dri2 \ 23 | xinput \ 24 | sync \ 25 | randr \ 26 | xtest \ 27 | res \ 28 | shape \ 29 | xevie \ 30 | glx \ 31 | xv \ 32 | xselinux \ 33 | xf86dri \ 34 | composite 35 | 36 | PYTHON=python2 37 | CLIENT=cpp_client.py 38 | XCBGEN=/usr/lib/python3.3/site-packages 39 | PROTODIR=/usr/share/xcb 40 | XMLPROTOS=$(PROTOS:%=%.xml) 41 | HPPPROTOS=$(XMLPROTOS:%.xml=%.hpp) 42 | 43 | all: ${XMLPROTOS} 44 | 45 | gch: ${HPPPROTOS} 46 | 47 | ${HPPPROTOS}: 48 | -${CXX} ${CXXFLAGS} ${LDFLAGS} -c $(if $(filter $@,xproto.hpp),x.hpp,$(@)) 49 | 50 | ${XMLPROTOS}: 51 | -${PYTHON} ${CLIENT} -p ${XCBGEN} ${PROTODIR}/$@ > $(if $(filter $@,xproto.xml),x.hpp,$(@:%.xml=%.hpp)) 52 | 53 | find: 54 | @ find ${PROTODIR} -iname '*.xml' -exec basename {} .xml \; 55 | 56 | clean: 57 | rm -f ${PROTOS:%=%.hpp} 58 | rm -f $(PROTOS:%=%.hpp.gch) 59 | 60 | .PHONY: clean find ${XMLPROTOS} ${HPPPROTOS} 61 | -------------------------------------------------------------------------------- /src/proto/TODO: -------------------------------------------------------------------------------- 1 | TODO: 2 | 3 | * Build with python 3 4 | 5 | * valueparams 6 | 7 | * serialized fields (e.g. xcb_sync_create_alarm_value_list_serialize) 8 | (is this necessary?) 9 | 10 | * specialize iterator for non-vector data structures: 11 | Instead of converting to vector, check if it is possible to send the data 12 | directly through the socket (e.g. map { key, value }: 13 | for (k,v : map) { socket_send(v); } ... 14 | 15 | * XInput Event handling: Am I doing this right? (Multiple switches etc.) 16 | 17 | * Adapter classes for drawable, window, pixmap, atom, font, etc. 18 | 19 | $ grep xidtype *.xml 20 | damage.xml: 21 | glx.xml: 22 | glx.xml: 23 | glx.xml: 24 | glx.xml: 25 | glx.xml: 26 | present.xml: 27 | randr.xml: 28 | randr.xml: 29 | randr.xml: 30 | randr.xml: 31 | record.xml: 32 | render.xml: 33 | render.xml: 34 | render.xml: 35 | shm.xml: 36 | sync.xml: 37 | sync.xml: 38 | sync.xml: 39 | xfixes.xml: 40 | xfixes.xml: 41 | xprint.xml: 42 | xproto.xml: 43 | xproto.xml: 44 | xproto.xml: 45 | xproto.xml: 46 | xproto.xml: 47 | xproto.xml: 48 | xproto.xml: 49 | xvmc.xml: 50 | xvmc.xml: 51 | xvmc.xml: 52 | xv.xml: 53 | xv.xml: 54 | -------------------------------------------------------------------------------- /src/proto/accessor.py: -------------------------------------------------------------------------------- 1 | from resource_classes import _resource_classes 2 | 3 | _templates = {} 4 | 5 | _templates['iter_fixed'] = \ 6 | """\ 7 | xpp::generic::iterator\ 11 | """ 12 | 13 | _templates['iter_variable'] = \ 14 | """\ 15 | xpp::generic::iterator\ 20 | """ 21 | 22 | _templates['list'] = \ 23 | """\ 24 | xpp::generic::list 28 | %s(void) 29 | { 30 | return xpp::generic::list(%s); 34 | }\ 35 | """ 36 | 37 | _templates['string_accessor'] = \ 38 | '''\ 39 | std::string 40 | %s(void) 41 | { 42 | return std::string(%s_%s(this->get().get()), 43 | %s_%s_length(this->get().get())); 44 | } 45 | ''' 46 | 47 | def _string_accessor(member, c_name): 48 | return _templates['string_accessor'] % \ 49 | (member, c_name, member, c_name, member) 50 | 51 | class Accessor(object): 52 | def __init__(self, is_fixed=False, is_string=False, is_variable=False, \ 53 | member="", c_type="", return_type="", iter_name="", c_name=""): 54 | 55 | self.is_fixed = is_fixed 56 | self.is_string = is_string 57 | self.is_variable = is_variable 58 | 59 | self.member = member 60 | self.c_type = c_type 61 | self.return_type = return_type 62 | self.iter_name = iter_name 63 | self.c_name = c_name 64 | 65 | self.object_type = self.c_type.replace("xcb_", "").replace("_t", "").upper() 66 | 67 | if self.c_type == "void": 68 | self.return_type = "Type" 69 | elif self.object_type in _resource_classes: 70 | self.return_type = self.member.capitalize() 71 | else: 72 | self.return_type = self.c_type 73 | 74 | def __str__(self): 75 | if self.is_fixed: 76 | return self.list(self.iter_fixed()) 77 | elif self.is_variable: 78 | return self.list(self.iter_variable()) 79 | elif self.is_string: 80 | return self.string() 81 | else: 82 | return "" 83 | 84 | 85 | def iter_fixed(self): 86 | return_type = self.return_type 87 | 88 | return _templates['iter_fixed'] \ 89 | % (return_type, 90 | self.c_name, self.member, 91 | self.c_name, self.member) 92 | 93 | 94 | def iter_variable(self): 95 | return _templates['iter_variable'] \ 96 | % (self.c_type, 97 | self.iter_name, 98 | self.iter_name, 99 | self.c_name, self.member) 100 | 101 | 102 | def list(self, iterator): 103 | template = " template 106 | if self.object_type in _resource_classes: 107 | template += ", " if template != "" else " template\n" if template != "" else "" 111 | 112 | c_tor_params = "this->m_c, this->get()" 113 | 114 | fst_iterator = "\n ".join(iterator.split('\n')) 115 | snd_iterator = "\n ".join(iterator.split('\n')) 116 | 117 | return template + _templates['list'] \ 118 | % (self.c_name, 119 | fst_iterator, 120 | self.member, 121 | self.c_name, 122 | snd_iterator, 123 | c_tor_params) 124 | 125 | def string(self): 126 | return _string_accessor(self.member, self.c_name) 127 | -------------------------------------------------------------------------------- /src/proto/cppcookie.py: -------------------------------------------------------------------------------- 1 | from utils import _n, _ext, _n_item, get_namespace 2 | 3 | _templates = {} 4 | 5 | _templates['void_cookie_function'] = \ 6 | '''\ 7 | %s\ 8 | void 9 | %s_checked(Connection && c%s) 10 | {%s\ 11 | xpp::generic::check( 12 | std::forward(c), 13 | %s_checked(std::forward(c)%s)); 14 | } 15 | 16 | %s\ 17 | void 18 | %s(Connection && c%s) 19 | {%s\ 20 | %s(std::forward(c)%s); 21 | } 22 | ''' 23 | 24 | def _void_cookie_function(ns, name, c_name, template, return_value, protos, calls, initializer): 25 | if len(template) == 0: template = "template\n" 26 | return _templates['void_cookie_function'] % \ 27 | ( template 28 | , name 29 | , protos 30 | , initializer 31 | , ns 32 | , c_name 33 | , calls 34 | , template 35 | , name 36 | , protos 37 | , initializer 38 | , c_name 39 | , calls 40 | ) 41 | 42 | _templates['cookie_static_getter'] = \ 43 | '''\ 44 | %s\ 45 | static 46 | %s 47 | cookie(xcb_connection_t * const c%s) 48 | {%s\ 49 | return base::cookie(c%s); 50 | } 51 | ''' 52 | 53 | def _cookie_static_getter(template, return_value, protos, calls, initializer): 54 | return _templates['cookie_static_getter'] % \ 55 | ( template 56 | , return_value 57 | , protos 58 | , initializer 59 | , calls 60 | ) 61 | 62 | class CppCookie(object): 63 | def __init__(self, namespace, is_void, name, reply, parameter_list): 64 | self.namespace = namespace 65 | self.is_void = is_void 66 | self.name = name 67 | self.reply = reply 68 | self.parameter_list = parameter_list 69 | self.request_name = _ext(_n_item(self.name[-1])) 70 | self.c_name = "xcb" \ 71 | + (("_" + get_namespace(namespace)) if namespace.is_ext else "") \ 72 | + "_" + self.request_name 73 | 74 | def comma(self): 75 | return self.parameter_list.comma() 76 | 77 | def calls(self, sort): 78 | return self.parameter_list.calls(sort) 79 | 80 | def protos(self, sort, defaults): 81 | return self.parameter_list.protos(sort, defaults) 82 | 83 | def iterator_template(self, indent=" ", tail="\n"): 84 | prefix = "template" + tail \ 89 | if len(self.parameter_list.iterator_templates) > 0 \ 90 | else "" 91 | 92 | def iterator_calls(self, sort): 93 | return self.parameter_list.iterator_calls(sort) 94 | 95 | def iterator_protos(self, sort, defaults): 96 | return self.parameter_list.iterator_protos(sort, defaults) 97 | 98 | def iterator_initializers(self): 99 | return self.parameter_list.iterator_initializers() 100 | 101 | def void_functions(self, protos, calls, template="", initializer=[]): 102 | inits = "" if len(initializer) > 0 else "\n" 103 | for i in initializer: 104 | inits += "\n" 105 | for line in i.split('\n'): 106 | inits += " " + line + "\n" 107 | 108 | return_value = "xcb_void_cookie_t" 109 | 110 | return _void_cookie_function(get_namespace(self.namespace), 111 | self.request_name, 112 | self.c_name, 113 | template, 114 | return_value, 115 | self.comma() + protos, 116 | self.comma() + calls, 117 | inits) 118 | 119 | 120 | def static_reply_methods(self, protos, calls, template="", initializer=[]): 121 | inits = "" if len(initializer) > 0 else "\n" 122 | for i in initializer: 123 | inits += "\n" 124 | for line in i.split('\n'): 125 | inits += " " + line + "\n" 126 | 127 | if self.is_void: return_value = "xcb_void_cookie_t" 128 | else: return_value = self.c_name + "_cookie_t" 129 | 130 | return _cookie_static_getter(template, 131 | return_value, 132 | self.comma() + protos, 133 | self.comma() + calls, 134 | inits) 135 | 136 | 137 | def make_static_getter(self): 138 | default = self.static_reply_methods(self.protos(False, False), self.calls(False)) 139 | 140 | if self.parameter_list.has_defaults: 141 | default = self.static_reply_methods(self.protos(True, True), self.calls(False)) 142 | 143 | wrapped = "" 144 | if self.parameter_list.want_wrap: 145 | wrapped = \ 146 | self.static_reply_methods(self.iterator_protos(True, True), 147 | self.iterator_calls(False), self.iterator_template(), 148 | self.iterator_initializers()) 149 | 150 | default_args = "" 151 | if self.parameter_list.is_reordered(): 152 | default_args = \ 153 | self.static_reply_methods(self.protos(True, True), self.calls(False)) 154 | 155 | result = "" 156 | 157 | if (self.parameter_list.has_defaults 158 | or self.parameter_list.is_reordered() 159 | or self.parameter_list.want_wrap): 160 | result += default 161 | 162 | if self.parameter_list.is_reordered(): 163 | result += "\n" + default_args 164 | 165 | if self.parameter_list.want_wrap: 166 | result += "\n" + wrapped 167 | 168 | return result 169 | 170 | def make_void_functions(self): 171 | default = self.void_functions(self.protos(False, False), self.calls(False)) 172 | 173 | if self.parameter_list.has_defaults: 174 | default = self.void_functions(self.protos(True, True), self.calls(False)) 175 | 176 | wrapped = "" 177 | if self.parameter_list.want_wrap: 178 | wrapped = \ 179 | self.void_functions(self.iterator_protos(True, True), 180 | self.iterator_calls(False), 181 | self.iterator_template(indent=""), 182 | self.iterator_initializers()) 183 | 184 | default_args = "" 185 | if self.parameter_list.is_reordered(): 186 | default_args = \ 187 | self.void_functions(self.protos(True, True), self.calls(False)) 188 | 189 | result = "" 190 | 191 | if (self.parameter_list.has_defaults 192 | or self.parameter_list.is_reordered() 193 | or self.parameter_list.want_wrap): 194 | result += default 195 | 196 | if self.parameter_list.is_reordered(): 197 | result += "\n" + default_args 198 | 199 | if self.parameter_list.want_wrap: 200 | result += "\n" + wrapped 201 | 202 | return result 203 | -------------------------------------------------------------------------------- /src/proto/cpperror.py: -------------------------------------------------------------------------------- 1 | from utils import \ 2 | get_namespace, \ 3 | get_ext_name, \ 4 | _n_item, \ 5 | _ext, \ 6 | _reserved_keywords 7 | 8 | _templates = {} 9 | 10 | _templates['error_dispatcher_class'] = \ 11 | '''\ 12 | namespace error { 13 | 14 | class dispatcher 15 | { 16 | public: 17 | %s\ 18 | %s\ 19 | 20 | void 21 | operator()(const std::shared_ptr &%s) const 22 | { 23 | %s\ 24 | } 25 | 26 | %s\ 27 | }; // class dispatcher 28 | 29 | }; // namespace error 30 | ''' 31 | 32 | def _error_dispatcher_class(typedef, ctors, switch, members, has_errors): 33 | return _templates['error_dispatcher_class'] % \ 34 | ( typedef 35 | , ctors 36 | , " error" if has_errors else "" 37 | , switch if has_errors else "" 38 | , members 39 | ) 40 | 41 | 42 | def error_dispatcher_class(namespace, cpperrors): 43 | ns = get_namespace(namespace) 44 | 45 | ctor_name = "dispatcher" 46 | 47 | typedef = [] 48 | ctors = [] 49 | members = [] 50 | opcode_switch = "error->error_code" 51 | 52 | typedef = [ "typedef xpp::%s::extension extension;\n" % ns ] 53 | 54 | # >>> if begin <<< 55 | if namespace.is_ext: 56 | opcode_switch = "error->error_code - m_first_error" 57 | 58 | members += \ 59 | [ "protected:" 60 | , " uint8_t m_first_error;" 61 | ] 62 | 63 | ctors = \ 64 | [ "%s(uint8_t first_error)" % (ctor_name) 65 | , " : m_first_error(first_error)" 66 | , "{}" 67 | , "" 68 | , "%s(const xpp::%s::extension & extension)" % (ctor_name, ns) 69 | , " : %s(extension->first_error)" % ctor_name 70 | , "{}" 71 | ] 72 | 73 | # >>> if end <<< 74 | 75 | if len(typedef) > 0: 76 | typedef = "\n".join(map(lambda s: " " + s, typedef)) + "\n" 77 | else: 78 | typedef = "" 79 | 80 | if len(ctors) > 0: 81 | ctors = "\n".join(map(lambda s: (" " if len(s) > 0 else "") + s, ctors)) + "\n" 82 | else: 83 | ctors = "" 84 | 85 | if len(members) > 0: 86 | members = "\n".join(map(lambda s: " " + s, members)) + "\n" 87 | else: 88 | members = "" 89 | 90 | switch = error_switch_cases(cpperrors, opcode_switch, "error") 91 | return _error_dispatcher_class(typedef, 92 | ctors, 93 | switch, 94 | members, 95 | len(cpperrors) > 0) 96 | 97 | def error_switch_cases(cpperrors, arg_switch, arg_error): 98 | cases = "" 99 | errors = cpperrors 100 | templ = [ " case %s: // %s" 101 | , " throw %s" + "(%s);" % arg_error 102 | , "" 103 | , "" 104 | ] 105 | 106 | cases += " switch (%s) {\n\n" % arg_switch 107 | for e in errors: 108 | cases += "\n".join(templ) % (e.opcode_name, e.opcode, e.scoped_name()) 109 | cases += " };\n" 110 | 111 | return cases 112 | 113 | 114 | class CppError(object): 115 | def __init__(self, error, namespace, name, c_name, opcode, opcode_name): 116 | self.error = error 117 | self.namespace = namespace 118 | self.c_name = c_name 119 | self.opcode = opcode 120 | self.opcode_name = opcode_name 121 | 122 | self.names = map(str.lower, _n_item(name[-1], True)) 123 | self.name = "_".join(map(str.lower, self.names)) 124 | 125 | self.nssopen = "" 126 | self.nssclose = "" 127 | self.scope = [] 128 | for name in self.names[0:-1]: 129 | if name in _reserved_keywords: name += "_" 130 | self.nssopen += " namespace %s {" % name 131 | self.nssclose += " };" 132 | self.scope.append(name) 133 | 134 | def get_name(self): 135 | return _reserved_keywords.get(self.name, self.name) 136 | 137 | 138 | def scoped_name(self): 139 | ns = get_namespace(self.namespace) 140 | return "xpp::" + ns + "::error::" + self.get_name() 141 | 142 | def make_class(self): 143 | ns = get_namespace(self.namespace) 144 | typedef = [] 145 | members = [] 146 | 147 | opcode_accessor = \ 148 | [ "static uint8_t opcode(void)" 149 | , "{" 150 | , " return %s;" % self.opcode_name 151 | , "}" 152 | ] 153 | 154 | if self.namespace.is_ext: 155 | opcode_accessor += \ 156 | [ "" 157 | , "static uint8_t opcode(uint8_t first_error)" 158 | , "{" 159 | , " return first_error + opcode();" 160 | , "}" 161 | , "" 162 | , "static uint8_t opcode(const xpp::%s::extension & extension)" % ns 163 | , "{" 164 | , " return opcode(extension->first_error);" 165 | , "}" 166 | ] 167 | 168 | members = \ 169 | [ "protected:" 170 | , " uint8_t m_first_error;" 171 | ] 172 | 173 | if len(opcode_accessor) > 0: 174 | opcode_accessor = "\n".join(map(lambda s: " " + s, opcode_accessor)) + "\n" 175 | else: 176 | opcode_accessor = "" 177 | 178 | if len(members) > 0: 179 | members = "\n" + "\n".join(map(lambda s: " " + s, members)) + "\n" 180 | else: 181 | members = "" 182 | 183 | if len(typedef) > 0: 184 | typedef = "\n".join(map(lambda s: " " + s, typedef)) + "\n\n" 185 | else: 186 | typedef = "" 187 | 188 | name = self.name 189 | if self.name in _reserved_keywords: name = self.name + "_" 190 | 191 | return \ 192 | ''' 193 | namespace error { 194 | class %s 195 | : public xpp::generic::error<%s, 196 | %s> 197 | { 198 | public: 199 | %s\ 200 | using xpp::generic::error<%s, %s>::error; 201 | 202 | virtual ~%s(void) {} 203 | 204 | %s 205 | static std::string description(void) 206 | { 207 | return std::string("%s"); 208 | } 209 | %s\ 210 | }; // class %s 211 | }; // namespace error 212 | ''' % (self.get_name(), # class %s 213 | self.get_name(), # : public xpp::generic::error<%s, 214 | self.c_name, # %s> 215 | typedef, 216 | self.get_name(), self.c_name, # using xpp::generic::error<%s, %s>::error; 217 | self.get_name(), # virtual ~%s(void) {} 218 | opcode_accessor, 219 | self.opcode_name, # static constexpr const char * opcode_literal 220 | members, 221 | self.get_name()) # // class %s 222 | -------------------------------------------------------------------------------- /src/proto/cppevent.py: -------------------------------------------------------------------------------- 1 | import sys # stderr 2 | 3 | from utils import \ 4 | get_namespace, \ 5 | get_ext_name, \ 6 | _n_item, \ 7 | _ext, \ 8 | _reserved_keywords 9 | 10 | from resource_classes import _resource_classes 11 | 12 | _field_accessor_template_specialization = \ 13 | '''\ 14 | template 15 | template<> 16 | %s 17 | %s::%s<%s>(void) const 18 | { 19 | return %s; 20 | }\ 21 | ''' 22 | 23 | _templates = {} 24 | 25 | _templates['field_accessor_template'] = \ 26 | '''\ 27 | template 28 | ReturnType 29 | %s(Parameter && ... parameter) const 30 | { 31 | using make = xpp::generic::factory::make%s), 33 | ReturnType, 34 | Parameter ...>; 35 | return make()(this->m_c, 36 | (*this)->%s, 37 | std::forward(parameter) ...); 38 | }\ 39 | ''' 40 | 41 | def _field_accessor_template(c_type, method_name, member): 42 | return _templates['field_accessor_template'] % \ 43 | ( c_type 44 | , method_name 45 | , member 46 | , member 47 | ) 48 | 49 | _templates['event_dispatcher_class'] = \ 50 | '''\ 51 | namespace event { 52 | 53 | template 54 | class dispatcher 55 | { 56 | public: 57 | %s\ 58 | %s\ 59 | 60 | template 61 | bool 62 | operator()(Handler%s, 63 | const std::shared_ptr &%s) const 64 | {\ 65 | %s 66 | return false; 67 | } 68 | 69 | %s\ 70 | }; // class dispatcher 71 | 72 | }; // namespace event 73 | ''' 74 | 75 | def _event_dispatcher_class(typedef, ctors, switch, members, has_events): 76 | return _templates['event_dispatcher_class'] % \ 77 | ( typedef 78 | , ctors 79 | , " handler" if has_events else "" 80 | , " event" if has_events else "" 81 | , switch if has_events else "" 82 | , members 83 | ) 84 | 85 | def event_dispatcher_class(namespace, cppevents): 86 | ns = get_namespace(namespace) 87 | 88 | ctor_name = "dispatcher" 89 | 90 | typedef = [] 91 | ctors = [] 92 | members = [] 93 | 94 | opcode_switch = "event->response_type & ~0x80" 95 | typedef = [ "typedef xpp::%s::extension extension;\n" % ns ] 96 | 97 | members = \ 98 | [ "protected:" 99 | , " Connection m_c;" 100 | ] 101 | 102 | ctors = \ 103 | [ "template" 104 | , "%s(C && c)" % ctor_name 105 | , " : m_c(std::forward(c))" 106 | , "{}" 107 | ] 108 | 109 | # >>> if begin <<< 110 | if namespace.is_ext: 111 | opcode_switch = "(event->response_type & ~0x80) - m_first_event" 112 | 113 | members += [ " uint8_t m_first_event;" ] 114 | 115 | ctors = \ 116 | [ "template" 117 | , "%s(C && c, uint8_t first_event)" % (ctor_name) 118 | , " : m_c(std::forward(c))" 119 | , " , m_first_event(first_event)" 120 | , "{}" 121 | , "" 122 | , "template" 123 | , "%s(C && c, const xpp::%s::extension & extension)" % (ctor_name, ns) 124 | , " : %s(std::forward(c), extension->first_event)" % ctor_name 125 | , "{}" 126 | ] 127 | 128 | # >>> if end <<< 129 | 130 | if len(typedef) > 0: 131 | typedef = "\n".join(map(lambda s: " " + s, typedef)) + "\n" 132 | else: 133 | typedef = "" 134 | 135 | if len(ctors) > 0: 136 | ctors = "\n".join(map(lambda s: (" " if len(s) > 0 else "") + s, ctors)) + "\n" 137 | else: 138 | ctors = "" 139 | 140 | if len(members) > 0: 141 | members = "\n".join(map(lambda s: " " + s, members)) + "\n" 142 | else: 143 | members = "" 144 | 145 | switch = event_switch_cases(cppevents, opcode_switch, "handler", "event", namespace) 146 | 147 | return _event_dispatcher_class(typedef, 148 | ctors, 149 | switch, 150 | members, 151 | len(cppevents) > 0) 152 | 153 | def event_switch_cases(cppevents, arg_switch, arg_handler, arg_event, ns): 154 | cases = "" 155 | first_event_arg = ", m_first_event" if ns.is_ext else "" 156 | templ = [ " case %s:" 157 | , " %s(" % arg_handler + "%s" + "(m_c%s, %s));" % (first_event_arg, arg_event) 158 | , " return true;" 159 | , "" 160 | , "" 161 | ] 162 | 163 | distinct_events = [[]] 164 | for e in cppevents: 165 | done = False 166 | for l in distinct_events: 167 | if e in l: 168 | continue 169 | else: 170 | l.append(e) 171 | done = True 172 | break 173 | 174 | if not done: 175 | distinct_events.append([e]) 176 | else: 177 | continue 178 | 179 | for l in distinct_events: 180 | cases += "\n switch (%s) {\n\n" % arg_switch 181 | for e in l: 182 | cases += "\n".join(templ) % (e.opcode_name, e.scoped_name()) 183 | cases += " };\n" 184 | 185 | return cases if len(cppevents) > 0 else "" 186 | 187 | ########## EVENT ########## 188 | 189 | class CppEvent(object): 190 | def __init__(self, opcode, opcode_name, c_name, namespace, name, fields): 191 | self.opcode = opcode 192 | self.opcode_name = opcode_name 193 | self.c_name = c_name 194 | self.namespace = namespace 195 | self.fields = fields 196 | 197 | self.names = map(str.lower, _n_item(name[-1], True)) 198 | self.name = "_".join(map(str.lower, self.names)) 199 | 200 | self.nssopen = "" 201 | self.nssclose = "" 202 | self.scope = [] 203 | for name in self.names[0:-1]: 204 | if name in _reserved_keywords: name += "_" 205 | self.nssopen += " namespace %s {" % name 206 | self.nssclose += " };" 207 | self.scope.append(name) 208 | 209 | def __cmp__(self, other): 210 | if self.opcode == other.opcode: 211 | return 0 212 | elif self.opcode < other.opcode: 213 | return -1 214 | else: 215 | return 1 216 | 217 | def get_name(self): 218 | return _reserved_keywords.get(self.name, self.name) 219 | 220 | 221 | def scoped_name(self): 222 | ns = get_namespace(self.namespace) 223 | return "xpp::" + ns + "::event::" + self.get_name() 224 | 225 | def make_class(self): 226 | member_accessors = [] 227 | member_accessors_special = [] 228 | for field in self.fields: 229 | if field.field_type[-1] in _resource_classes: 230 | template_name = field.field_name.capitalize() 231 | c_type = field.c_field_type 232 | method_name = field.field_name.lower() 233 | if (method_name == self.get_name() 234 | or method_name in _reserved_keywords): 235 | method_name += "_" 236 | member = field.c_field_name 237 | 238 | member_accessors.append(_field_accessor_template(c_type, method_name, member)) 239 | 240 | ns = get_namespace(self.namespace) 241 | 242 | extension = "xpp::%s::extension" % ns 243 | 244 | ctor = \ 245 | [ "template" 246 | , "%s(C && c," % self.get_name() 247 | , (" " * len(self.get_name())) + " const std::shared_ptr & event)" 248 | , " : base(event)" 249 | , " , m_c(std::forward(c))" 250 | , "{}" 251 | ] 252 | 253 | m_first_event = "" 254 | 255 | typedef = [ "typedef xpp::%s::extension extension;" % ns ] 256 | 257 | description = \ 258 | [ "static std::string description(void)" 259 | , "{" 260 | , " return std::string(\"%s\");" % self.opcode_name 261 | , "}" 262 | ] 263 | 264 | opcode_accessor = \ 265 | [ "static uint8_t opcode(void)" 266 | , "{" 267 | , " return %s;" % self.opcode_name 268 | , "}" 269 | ] 270 | 271 | first_event = [] 272 | 273 | if self.namespace.is_ext: 274 | opcode_accessor += \ 275 | [ "" 276 | , "static uint8_t opcode(uint8_t first_event)" 277 | , "{" 278 | , " return first_event + opcode();" 279 | , "}" 280 | , "" 281 | , "static uint8_t opcode(const xpp::%s::extension & extension)" % ns 282 | , "{" 283 | , " return opcode(extension->first_event);" 284 | , "}" 285 | ] 286 | 287 | first_event = \ 288 | [ "uint8_t first_event(void)" 289 | , "{" 290 | , " return m_first_event;" 291 | , "}" 292 | ] 293 | 294 | ctor = \ 295 | [ "template" 296 | , "%s(C && c," % self.get_name() 297 | , (" " * len(self.get_name())) + " uint8_t first_event," 298 | , (" " * len(self.get_name())) + " const std::shared_ptr & event)" 299 | , " : base(event)" 300 | , " , m_c(std::forward(c))" 301 | , " , m_first_event(first_event)" 302 | , "{}" 303 | ] 304 | 305 | m_first_event = " const uint8_t m_first_event;\n" 306 | 307 | if len(opcode_accessor) > 0: 308 | opcode_accessor = "\n".join(map(lambda s: " " + s, opcode_accessor)) + "\n" 309 | else: 310 | opcode_accessor = "" 311 | 312 | if len(ctor) > 0: 313 | ctor = "\n".join(map(lambda s: " " + s, ctor)) + "\n" 314 | else: 315 | ctor = "" 316 | 317 | if len(typedef) > 0: 318 | typedef = "\n".join(map(lambda s: " " + s, typedef)) + "\n\n" 319 | else: 320 | typedef = "" 321 | 322 | if len(member_accessors) > 0: 323 | member_accessors = "\n" + "\n\n".join(member_accessors) + "\n\n" 324 | member_accessors_special = "\n" + "\n\n".join(member_accessors_special) + "\n\n" 325 | else: 326 | member_accessors = "" 327 | member_accessors_special = "" 328 | 329 | if len(description) > 0: 330 | description = "\n" + "\n".join(map(lambda s: " " + s, description)) + "\n" 331 | else: 332 | description = "" 333 | 334 | if len(first_event) > 0: 335 | first_event = "\n" + "\n".join(map(lambda s: " " + s, first_event)) + "\n" 336 | else: 337 | first_event = "" 338 | 339 | return \ 340 | ''' 341 | namespace event { 342 | template 343 | class %s 344 | : public xpp::generic::event<%s> 345 | { 346 | public: 347 | %s\ 348 | typedef xpp::generic::event<%s> base; 349 | 350 | %s\ 351 | 352 | virtual ~%s(void) {} 353 | 354 | %s\ 355 | %s\ 356 | %s\ 357 | %s\ 358 | protected: 359 | Connection m_c; 360 | %s\ 361 | }; // class %s 362 | %s\ 363 | }; // namespace event 364 | ''' % (self.get_name(), # class %s 365 | self.c_name, # %s> 366 | typedef, 367 | self.c_name, # typedef xpp::generic::event<%s>::base; 368 | ctor, 369 | self.get_name(), # virtual ~%s(void) {} 370 | opcode_accessor, 371 | description, 372 | first_event, 373 | member_accessors, 374 | m_first_event, 375 | self.get_name(), # // class %s 376 | member_accessors_special) 377 | -------------------------------------------------------------------------------- /src/proto/cppreply.py: -------------------------------------------------------------------------------- 1 | from utils import _n, _ext, _n_item, get_namespace 2 | from resource_classes import _resource_classes 3 | 4 | _templates = {} 5 | 6 | _templates['reply_class'] = \ 7 | '''\ 8 | namespace reply { 9 | 10 | namespace detail { 11 | 12 | template 15 | class %s 16 | : public xpp::generic::reply<%s, 17 | Connection, 18 | Check, 19 | SIGNATURE(%s_reply), 20 | CookieFunction> 21 | { 22 | public: 23 | typedef xpp::generic::reply<%s, 24 | Connection, 25 | Check, 26 | SIGNATURE(%s_reply), 27 | CookieFunction> 28 | base; 29 | 30 | template 31 | %s(C && c, Parameter && ... parameter) 32 | : base(std::forward(c), std::forward(parameter) ...) 33 | {} 34 | 35 | %s\ 36 | %s\ 37 | }; // class %s 38 | 39 | }; // namespace detail 40 | 41 | namespace checked { 42 | template 43 | using %s = detail::%s< 44 | Connection, xpp::generic::checked_tag, 45 | SIGNATURE(%s)>; 46 | }; // namespace checked 47 | 48 | namespace unchecked { 49 | template 50 | using %s = detail::%s< 51 | Connection, xpp::generic::unchecked_tag, 52 | SIGNATURE(%s_unchecked)>; 53 | }; // namespace unchecked 54 | 55 | }; // namespace reply 56 | ''' 57 | 58 | def _reply_class(name, c_name, ns, cookie, accessors): 59 | return _templates['reply_class'] % \ 60 | ( name 61 | , name # base class 62 | , c_name # %s_reply 63 | , name # typedef 64 | , c_name # %s_reply 65 | , name # c'tor 66 | , cookie.make_static_getter() 67 | , accessors 68 | , name # // class %s 69 | , name # checked { using %s = 70 | , name # checked { detail::%s 71 | , c_name # checked { SIGNATURE 72 | , name # unchecked { using %s = 73 | , name # unchecked { detail::%s 74 | , c_name # unchecked { SIGNATURE 75 | ) 76 | 77 | _templates['reply_member_accessor'] = \ 78 | '''\ 79 | template 80 | ReturnType 81 | %s(Parameter && ... parameter) 82 | { 83 | using make = xpp::generic::factory::makeget()->%s), 85 | ReturnType, 86 | Parameter ...>; 87 | return make()(this->m_c, 88 | this->get()->%s, 89 | std::forward(parameter) ...); 90 | } 91 | ''' 92 | 93 | def _reply_member_accessor(request_name, name, c_type, template_type): 94 | return _templates['reply_member_accessor'] % \ 95 | ( c_type 96 | , name 97 | , name 98 | , name 99 | ) 100 | 101 | class CppReply(object): 102 | def __init__(self, namespace, name, cookie, reply, accessors, parameter_list): 103 | self.namespace = namespace 104 | self.name = name 105 | self.reply = reply 106 | self.cookie = cookie 107 | self.accessors = accessors 108 | self.parameter_list = parameter_list 109 | self.request_name = _ext(_n_item(self.name[-1])) 110 | self.c_name = "xcb" \ 111 | + (("_" + get_namespace(namespace)) if namespace.is_ext else "") \ 112 | + "_" + self.request_name 113 | 114 | def make_accessors(self): 115 | return "\n".join(map(lambda a: "\n%s\n" % a, self.accessors)) 116 | 117 | def make(self): 118 | accessors = [self.make_accessors()] 119 | naccessors = len(self.accessors) 120 | 121 | for field in self.reply.fields: 122 | if (field.field_type[-1] in _resource_classes 123 | and not field.type.is_list 124 | and not field.type.is_container): 125 | 126 | naccessors = naccessors + 1 127 | 128 | name = field.field_name.lower() 129 | c_type = field.c_field_type 130 | template_type = field.field_name.capitalize() 131 | 132 | accessors.append(_reply_member_accessor(self.request_name, name, c_type, template_type)) 133 | 134 | result = "" 135 | result += _reply_class( 136 | self.request_name, self.c_name, get_namespace(self.namespace), 137 | self.cookie, "\n".join(accessors)) 138 | return result 139 | -------------------------------------------------------------------------------- /src/proto/cpprequest.py: -------------------------------------------------------------------------------- 1 | # vim: set ts=4 sws=4 sw=4: 2 | 3 | # from utils import * 4 | from utils import _n, _ext, _n_item, get_namespace 5 | from parameter import * 6 | from resource_classes import _resource_classes 7 | from cppreply import CppReply 8 | from cppcookie import CppCookie 9 | 10 | _templates = {} 11 | 12 | _templates['void_request_function'] = \ 13 | '''\ 14 | template 15 | void 16 | %s_checked(Connection && c, Parameter && ... parameter) 17 | { 18 | xpp::generic::check( 19 | std::forward(c), 20 | %s_checked( 21 | std::forward(c), 22 | std::forward(parameter) ...)); 23 | } 24 | 25 | template 26 | void 27 | %s(Parameter && ... parameter) 28 | { 29 | %s(std::forward(parameter) ...); 30 | } 31 | ''' 32 | 33 | def _void_request_function(ns, name, c_name): 34 | return _templates['void_request_function'] % \ 35 | ( name 36 | , ns 37 | , c_name 38 | , name 39 | , c_name 40 | ) 41 | 42 | _templates['reply_request_function'] = \ 43 | '''\ 44 | template 45 | reply::checked::%s 46 | %s(Connection && c, Parameter && ... parameter) 47 | { 48 | return reply::checked::%s( 49 | std::forward(c), std::forward(parameter) ...); 50 | } 51 | 52 | template 53 | reply::unchecked::%s 54 | %s_unchecked(Connection && c, Parameter && ... parameter) 55 | { 56 | return reply::unchecked::%s( 57 | std::forward(c), std::forward(parameter) ...); 58 | } 59 | ''' 60 | 61 | def _reply_request_function(name): 62 | return _templates['reply_request_function'] % \ 63 | ( name 64 | , name 65 | , name 66 | , name 67 | , name 68 | , name) 69 | 70 | _templates['inline_reply_class'] = \ 71 | '''\ 72 | template 73 | auto 74 | %s(Parameter && ... parameter) const 75 | -> reply::checked::%s 76 | { 77 | return xpp::%s::%s( 78 | connection(), 79 | %s\ 80 | std::forward(parameter) ...); 81 | } 82 | 83 | template 84 | auto 85 | %s_unchecked(Parameter && ... parameter) const 86 | -> reply::unchecked::%s 87 | { 88 | return xpp::%s::%s_unchecked( 89 | connection(), 90 | %s\ 91 | std::forward(parameter) ...); 92 | } 93 | ''' 94 | 95 | def _inline_reply_class(request_name, method_name, member, ns): 96 | return _templates['inline_reply_class'] % \ 97 | ( method_name 98 | , request_name 99 | , ns 100 | , request_name 101 | , member 102 | , method_name 103 | , request_name 104 | , ns 105 | , request_name 106 | , member 107 | ) 108 | 109 | _templates['inline_void_class'] = \ 110 | '''\ 111 | template 112 | void 113 | %s_checked(Parameter && ... parameter) const 114 | { 115 | xpp::%s::%s_checked(connection(), 116 | %s\ 117 | std::forward(parameter) ...); 118 | } 119 | 120 | template 121 | void 122 | %s(Parameter && ... parameter) const 123 | { 124 | xpp::%s::%s(connection(), 125 | %s\ 126 | std::forward(parameter) ...); 127 | } 128 | ''' 129 | 130 | def _inline_void_class(request_name, method_name, member, ns): 131 | return _templates['inline_void_class'] % \ 132 | ( method_name 133 | , ns 134 | , request_name 135 | , member 136 | , method_name 137 | , ns 138 | , request_name 139 | , member 140 | ) 141 | 142 | _replace_special_classes = \ 143 | { "gcontext" : "gc" } 144 | 145 | def replace_class(method, class_name): 146 | cn = _replace_special_classes.get(class_name, class_name) 147 | return method.replace("_" + cn, "") 148 | 149 | class CppRequest(object): 150 | def __init__(self, request, name, is_void, namespace, reply): 151 | self.request = request 152 | self.name = name 153 | self.request_name = _ext(_n_item(self.request.name[-1])) 154 | self.is_void = is_void 155 | self.namespace = namespace 156 | self.reply = reply 157 | self.c_namespace = \ 158 | "" if namespace.header.lower() == "xproto" \ 159 | else get_namespace(namespace) 160 | self.accessors = [] 161 | self.parameter_list = ParameterList() 162 | 163 | self.c_name = "xcb" \ 164 | + (("_" + get_namespace(namespace)) if namespace.is_ext else "") \ 165 | + "_" + self.request_name 166 | 167 | def add(self, param): 168 | self.parameter_list.add(param) 169 | 170 | def make_wrapped(self): 171 | self.parameter_list.make_wrapped() 172 | 173 | def make_class(self): 174 | cppcookie = CppCookie(self.namespace, self.is_void, self.request.name, self.reply, self.parameter_list) 175 | 176 | if self.is_void: 177 | void_functions = cppcookie.make_void_functions() 178 | if len(void_functions) > 0: 179 | return void_functions 180 | else: 181 | return _void_request_function(get_namespace(self.namespace), self.request_name, self.c_name) 182 | 183 | else: 184 | cppreply = CppReply(self.namespace, self.request.name, cppcookie, self.reply, self.accessors, self.parameter_list) 185 | return cppreply.make() + "\n\n" + _reply_request_function(self.request_name) 186 | 187 | def make_object_class_inline(self, is_connection, class_name=""): 188 | member = "" 189 | method_name = self.name 190 | if not is_connection: 191 | member = "resource(),\n" 192 | method_name = replace_class(method_name, class_name) 193 | 194 | if self.is_void: 195 | return _inline_void_class(self.request_name, method_name, member, get_namespace(self.namespace)) 196 | else: 197 | return _inline_reply_class(self.request_name, method_name, member, get_namespace(self.namespace)) 198 | -------------------------------------------------------------------------------- /src/proto/extensionclass.py: -------------------------------------------------------------------------------- 1 | from utils import \ 2 | get_namespace, \ 3 | get_ext_name, \ 4 | _n_item, \ 5 | _ext 6 | 7 | class ExtensionClass(object): 8 | def __init__(self, namespace): 9 | self.namespace = namespace 10 | 11 | def make_class(self): 12 | # if not self.namespace.is_ext: 13 | # return "" 14 | # else: 15 | ns = get_namespace(self.namespace) 16 | if self.namespace.is_ext: 17 | base = "\n : public xpp::generic::extension\n" % ns 18 | ctor = " using base = xpp::generic::extension;\n" % ns + \ 19 | " using base::base;\n" 20 | else: 21 | base = " " 22 | ctor = "" 23 | 24 | return \ 25 | '''\ 26 | template 27 | class interface; 28 | 29 | namespace event { template class dispatcher; }; 30 | namespace error { class dispatcher; }; 31 | 32 | class extension%s{ 33 | public: 34 | %s\ 35 | template 36 | using interface = xpp::%s::interface; 37 | template 38 | using event_dispatcher = xpp::%s::event::dispatcher; 39 | using error_dispatcher = xpp::%s::error::dispatcher; 40 | };\ 41 | ''' % (base, 42 | ctor, 43 | ns, # typedef xpp::interface::%s interface; 44 | ns, # typedef xpp::event::dispatcher::%s dispatcher; 45 | ns) # typedef xpp::error::dispatcher::%s dispatcher; 46 | -------------------------------------------------------------------------------- /src/proto/interfaceclass.py: -------------------------------------------------------------------------------- 1 | # vim: set ts=4 sws=4 sw=4: 2 | 3 | from utils import \ 4 | get_namespace, \ 5 | get_ext_name, \ 6 | _n_item, \ 7 | _ext 8 | 9 | from cppevent import event_dispatcher_class 10 | from cpperror import error_dispatcher_class 11 | 12 | _templates = {} 13 | 14 | _templates['interface_class'] = \ 15 | """\ 16 | template 17 | class interface 18 | { 19 | protected: 20 | Connection 21 | connection(void) const 22 | { 23 | return static_cast(this)->connection(); 24 | } 25 | 26 | public: 27 | %s\ 28 | 29 | virtual ~interface(void) {} 30 | 31 | const interface & 32 | %s(void) 33 | { 34 | return *this; 35 | } 36 | 37 | %s\ 38 | }; // class interface 39 | """ 40 | 41 | _ignore_events = \ 42 | { "XCB_PRESENT_GENERIC" } 43 | 44 | ########## INTERFACECLASS ########## 45 | 46 | class InterfaceClass(object): 47 | def __init__(self): 48 | self.requests = [] 49 | self.events = [] 50 | self.errors = [] 51 | 52 | def add(self, request): 53 | self.requests.append(request) 54 | 55 | def add_event(self, event): 56 | if event.opcode_name not in _ignore_events: 57 | self.events.append(event) 58 | 59 | def add_error(self, error): 60 | self.errors.append(error) 61 | 62 | def set_namespace(self, namespace): 63 | self.namespace = namespace 64 | 65 | def make_proto(self): 66 | ns = get_namespace(self.namespace) 67 | methods = "" 68 | for request in self.requests: 69 | methods += request.make_object_class_inline(True) + "\n\n" 70 | 71 | typedef = [] 72 | if self.namespace.is_ext: 73 | typedef = [ "typedef xpp::%s::extension extension;" % ns ] 74 | 75 | if len(typedef) > 0: 76 | typedef = "".join(map(lambda s: " " + s, typedef)) + "\n\n" 77 | else: 78 | typedef = "" 79 | 80 | 81 | return (_templates['interface_class'] \ 82 | % (typedef, ns, methods)) + \ 83 | '\n' + event_dispatcher_class(self.namespace, self.events) + \ 84 | '\n' + error_dispatcher_class(self.namespace, self.errors) 85 | 86 | ########## INTERFACECLASS ########## 87 | -------------------------------------------------------------------------------- /src/proto/objectclass.py: -------------------------------------------------------------------------------- 1 | # vim: set ts=4 sws=4 sw=4: 2 | 3 | import sys # stderr 4 | import copy # deepcopy 5 | 6 | from utils import \ 7 | get_namespace, \ 8 | get_ext_name, \ 9 | _n_item, \ 10 | _ext 11 | 12 | class ObjectClass(object): 13 | def __init__(self, name): 14 | self.name = name 15 | self.requests = [] 16 | 17 | def add(self, request): 18 | if (len(request.parameter_list.parameter) > 0 19 | and request.parameter_list.parameter[0].c_type == self.c_name): 20 | request_copy = copy.deepcopy(request) 21 | request_copy.parameter_list.parameter.pop(0) 22 | request_copy.make_wrapped() 23 | self.requests.append(request_copy) 24 | 25 | def set_namespace(self, namespace): 26 | self.namespace = namespace 27 | name = (get_namespace(namespace) + "_") if namespace.is_ext else "" 28 | self.c_name = "xcb_%s_t" % (name + self.name.lower()) 29 | 30 | def make_inline(self): 31 | ns = get_namespace(self.namespace) 32 | name = self.name.lower() 33 | c_name = self.c_name 34 | methods = "" 35 | 36 | for request in self.requests: 37 | methods += request.make_object_class_inline(False, self.name.lower()) + "\n\n" 38 | 39 | if methods == "": 40 | return "" 41 | else: 42 | return \ 43 | """\ 44 | template 45 | class %s 46 | { 47 | protected: 48 | Connection 49 | connection(void) const 50 | { 51 | return static_cast(this)->connection(); 52 | } 53 | 54 | const %s & 55 | resource(void) const 56 | { 57 | return static_cast(this)->resource(); 58 | } 59 | 60 | public: 61 | virtual ~%s(void) {} 62 | 63 | %s 64 | }; // class %s 65 | """ % (name, # class %s 66 | c_name, # %s resource(void) { ... } 67 | name, # virtual ~%s(void) 68 | methods, 69 | name) # }; // class %s 70 | -------------------------------------------------------------------------------- /src/proto/parameter.py: -------------------------------------------------------------------------------- 1 | # vim: set ts=4 sws=4 sw=4: 2 | 3 | import sys # stderr 4 | 5 | _templates = {} 6 | 7 | _templates['initializer'] = \ 8 | '''\ 9 | typedef typename value_type<%s, ! std::is_pointer<%s>::value>::type 10 | vector_type; 11 | std::vector %s = 12 | { value_iterator<%s>(%s), value_iterator<%s>(%s) }; 13 | ''' 14 | 15 | def _initializer(iter_type, c_name, iter_begin, iter_end): 16 | return _templates['initializer'] % \ 17 | ( iter_type 18 | , iter_type 19 | , c_name 20 | , iter_type 21 | , iter_begin 22 | , iter_type 23 | , iter_end 24 | ) 25 | 26 | class ParameterList(object): 27 | def __init__(self): 28 | self.want_wrap = False 29 | self.has_defaults = False 30 | self.parameter = [] 31 | self.wrap_calls = [] 32 | self.wrap_protos = [] 33 | self.iter_calls = [] 34 | self.iter_2nd_lvl_calls = [] 35 | self.iter_protos = [] 36 | self.templates = [] 37 | self.iterator_templates = [] 38 | self.initializer = [] 39 | 40 | def add(self, param): 41 | self.has_defaults = param.default != None 42 | self.parameter.append(param) 43 | 44 | def comma(self): 45 | return "" if len(self.parameter) == 0 else ", " 46 | 47 | def is_reordered(self): 48 | tmp = sorted(self.parameter, cmp=lambda p1, p2: cmp(p1.default, p2.default)) 49 | return tmp != self.parameter 50 | 51 | def calls(self, sort, params=None): 52 | ps = self.parameter if params == None else params 53 | if sort: 54 | tmp = sorted(ps, cmp=lambda p1, p2: cmp(p1.default, p2.default)) 55 | ps = tmp 56 | calls = map(lambda p: p.call(), ps) 57 | return "" if len(calls) == 0 else ", ".join(calls) 58 | 59 | def protos(self, sort, defaults, params=None): 60 | if defaults: sort = True 61 | ps = self.parameter if params == None else params 62 | if sort: 63 | tmp = sorted(ps, cmp=lambda p1, p2: cmp(p1.default, p2.default)) 64 | ps = tmp 65 | protos = map(lambda p: p.proto(defaults), ps) 66 | return "" if len(protos) == 0 else ", ".join(protos) 67 | 68 | def iterator_initializers(self): 69 | return self.initializer 70 | 71 | def make_wrapped(self): 72 | self.wrap_calls = [] 73 | self.wrap_protos = [] 74 | self.iter_calls = [] 75 | self.iter_2nd_lvl_calls = [] 76 | self.iter_protos = [] 77 | self.initializer = [] 78 | self.templates = [] 79 | self.iterator_templates = [] 80 | 81 | lenfields = {} 82 | # if a parameter is removed, take reduced parameter size into account 83 | adjust = 0 84 | for index, param in enumerate(self.parameter): 85 | prev = index - adjust - 1 86 | 87 | if param.field.type.is_list: 88 | name = param.field.type.expr.lenfield_name 89 | if lenfields.has_key(name): 90 | lenfields[name].append(param.c_name) 91 | else: 92 | lenfields[name] = [ param.c_name ] 93 | 94 | # sys.stderr.write("list: %s %s\n\n" 95 | # % ( param.field.type.expr.lenfield_type 96 | # , param.field.type.expr.lenfield_name 97 | # )) 98 | 99 | # SetGamma: takes 1 size, but 3 value lists 100 | # if param.field.type.is_list and prev >= 0: 101 | if (param.is_const and param.is_pointer 102 | and prev >= 0 103 | and self.parameter[prev].c_name == param.c_name + "_len"): 104 | 105 | adjust = adjust + 1 106 | self.want_wrap = True 107 | self.wrap_calls.pop(prev) 108 | self.wrap_protos.pop(prev) 109 | self.iter_calls.pop(prev) 110 | self.iter_2nd_lvl_calls.pop(prev) 111 | self.iter_protos.pop(prev) 112 | 113 | prev_type = self.parameter[prev].c_type 114 | if param.c_type == 'char': 115 | 116 | def append_proto_string(list): 117 | list.append(Parameter(None, \ 118 | c_type='const std::string &', 119 | c_name=param.c_name)) 120 | 121 | def append_call_string(list): 122 | list.append(Parameter(None, \ 123 | c_name="static_cast<" + prev_type + ">(" \ 124 | + param.c_name + '.length())')) 125 | 126 | list.append(Parameter(None, \ 127 | c_name=param.c_name + '.c_str()')) 128 | 129 | append_proto_string(self.wrap_protos) 130 | append_proto_string(self.iter_protos) 131 | append_call_string(self.wrap_calls) 132 | append_call_string(self.iter_calls) 133 | append_call_string(self.iter_2nd_lvl_calls) 134 | 135 | else: 136 | param_type = param.c_type 137 | if param_type == "void": 138 | param_type = "Type_" + str(index) 139 | self.templates.append(param_type) 140 | 141 | prev_type = self.parameter[prev].c_type 142 | 143 | ### std::vector 144 | self.wrap_protos.append(Parameter(None, \ 145 | c_type='const std::vector<' + param_type + '> &', 146 | c_name=param.c_name)) 147 | 148 | self.wrap_calls.append(Parameter(None, \ 149 | c_name="static_cast<" + prev_type + ">(" \ 150 | + param.c_name + '.size())')) 151 | 152 | self.wrap_calls.append(Parameter(None, \ 153 | c_name=param.c_name + '.data()')) 154 | 155 | ### Iterator 156 | iter_type = param.c_name.capitalize() + "_Iterator" 157 | iter_begin = param.c_name + "_begin" 158 | iter_end = param.c_name + "_end" 159 | 160 | if len(self.templates) > 0: 161 | self.templates[-1] += " = typename " + iter_type + "::value_type" 162 | self.iterator_templates.append(iter_type) 163 | 164 | self.iter_protos.append(Parameter(None, \ 165 | c_type=iter_type, 166 | c_name=iter_begin)) 167 | 168 | self.iter_protos.append(Parameter(None, \ 169 | c_type=iter_type, 170 | c_name=iter_end)) 171 | 172 | self.iter_calls.append(Parameter(None, \ 173 | c_name="static_cast<" + prev_type + ">(" \ 174 | + param.c_name + '.size())')) 175 | 176 | self.iter_calls.append(Parameter(None, \ 177 | c_name='const_cast(' \ 178 | + param.c_name + '.data())')) 179 | 180 | self.iter_2nd_lvl_calls.append(Parameter(None, \ 181 | c_name=iter_begin)) 182 | 183 | self.iter_2nd_lvl_calls.append(Parameter(None, \ 184 | c_name=iter_end)) 185 | 186 | # vector_type = \ 187 | # '''\ 188 | # typename value_type<%s, 189 | # ! std::is_pointer<%s>::value 190 | # >::type\ 191 | # ''' % (iter_type, iter_type) 192 | 193 | # self.initializer.append( \ 194 | # "std::vector<%s> %s = { value_iterator<%s>(%s), \ 195 | # value_iterator<%s>(%s) };" \ 196 | # % (vector_type, param.c_name, 197 | # iter_type, iter_begin, 198 | # iter_type, iter_end)) 199 | 200 | self.initializer.append( 201 | _initializer(iter_type, param.c_name, iter_begin, iter_end)) 202 | 203 | else: 204 | self.wrap_calls.append(param) 205 | self.wrap_protos.append(param) 206 | self.iter_calls.append(param) 207 | self.iter_2nd_lvl_calls.append(param) 208 | self.iter_protos.append(param) 209 | 210 | # end: for index, param in enumerate(self.parameter): 211 | 212 | for k, v in lenfields.items(): 213 | if len(v) > 1: 214 | sys.stderr.write("list: %s, %s\n" % (k, v)) 215 | 216 | 217 | def wrapped_calls(self, sort): 218 | return self.calls(sort, params=self.wrap_calls) 219 | 220 | def wrapped_protos(self, sort, defaults): 221 | return self.protos(sort, defaults, params=self.wrap_protos) 222 | 223 | def iterator_calls(self, sort): 224 | return self.calls(sort, params=self.iter_calls) 225 | 226 | def iterator_2nd_lvl_calls(self, sort): 227 | return self.calls(sort, params=self.iter_2nd_lvl_calls) 228 | 229 | def iterator_protos(self, sort, defaults): 230 | return self.protos(sort, defaults, params=self.iter_protos) 231 | 232 | 233 | 234 | _default_parameter_values = \ 235 | { "xcb_timestamp_t" : "XCB_TIME_CURRENT_TIME" } 236 | 237 | class Parameter(object): 238 | def __init__(self, field, c_type="", c_name="", verbose=False): 239 | self.field = field 240 | if field != None: 241 | self.c_type = field.c_field_type 242 | self.c_name = field.c_field_name 243 | self.is_const = field.c_field_const_type == "const " + field.c_field_type 244 | self.is_pointer = field.c_pointer != " " 245 | # self.serialize = field.type.need_serialize 246 | self.default = _default_parameter_values.get(self.c_type) 247 | self.with_default = True 248 | if verbose: 249 | sys.stderr.write("c_type: %s; c_name: %s; default: %s\n" \ 250 | % (self.c_type, self.c_name, self.default)) 251 | 252 | else: 253 | self.c_type = c_type 254 | self.c_name = c_name 255 | self.is_const = False 256 | self.is_pointer = False 257 | # self.serialize = field.type.need_serialize 258 | self.default = _default_parameter_values.get(self.c_type) 259 | self.with_default = True 260 | 261 | def call(self): 262 | return self.c_name 263 | 264 | def proto(self, with_default): 265 | c_type = ("const " if self.is_const else "") \ 266 | + self.c_type \ 267 | + (" *" if self.is_pointer else "") 268 | param = " = " + self.default if with_default and self.default != None else "" 269 | return c_type + " " + self.c_name + param 270 | -------------------------------------------------------------------------------- /src/proto/resource_classes.py: -------------------------------------------------------------------------------- 1 | _resource_classes = \ 2 | { 3 | ### XPROTO ### 4 | "WINDOW" 5 | , "PIXMAP" 6 | , "CURSOR" 7 | , "FONT" 8 | , "GCONTEXT" 9 | , "COLORMAP" 10 | , "ATOM" 11 | , "DRAWABLE" 12 | , "FONTABLE" 13 | ### XPROTO ### 14 | 15 | ### DAMAGE ### 16 | , "DAMAGE" 17 | ### DAMAGE ### 18 | 19 | ### GLX, RECORD, XVMC ### 20 | , "CONTEXT" 21 | ### GLX, RECORD, XVMC ### 22 | 23 | ### GLX ### 24 | # , "PIXMAP" # already in XPROTO 25 | # , "CONTEXT" 26 | , "PBUFFER" 27 | # , "WINDOW" # already in XPROTO 28 | , "FBCONFIG" 29 | ### GLX ### 30 | 31 | ### PRESENT ### 32 | , "EVENT" 33 | ### PRESENT ### 34 | 35 | ### RANDR ### 36 | , "MODE" 37 | , "CRTC" 38 | , "OUTPUT" 39 | , "PROVIDER" 40 | ### RANDR ### 41 | 42 | ### RECORD ### 43 | # , "CONTEXT" 44 | ### RECORD ### 45 | 46 | ### RENDER ### 47 | , "GLYPHSET" 48 | , "PICTURE" 49 | , "PICTFORMAT" 50 | ### RENDER ### 51 | 52 | ### SHM ### 53 | , "SEG" 54 | ### SHM ### 55 | 56 | ### SYNC ### 57 | , "ALARM" 58 | , "COUNTER" 59 | , "FENCE" 60 | ### SYNC ### 61 | 62 | ### XFIXES ### 63 | , "REGION" 64 | , "BARRIER" 65 | ### XFIXES ### 66 | 67 | ### XPRINT ### 68 | , "PCONTEXT" 69 | ### XPRINT ### 70 | 71 | ### XVMC ### 72 | # , "CONTEXT" 73 | , "SURFACE" 74 | , "SUBPICTURE" 75 | ### XVMC ### 76 | 77 | ### XV ### 78 | , "PORT" 79 | , "ENCODING" 80 | ### XV ### 81 | } 82 | -------------------------------------------------------------------------------- /src/proto/utils.py: -------------------------------------------------------------------------------- 1 | import re # compile 2 | 3 | _reserved_keywords = {'class' : '_class', 4 | 'new' : '_new', 5 | 'delete': '_delete', 6 | 'default' : '_default', 7 | 'private' : '_private', 8 | 'explicit': '_explicit'} 9 | 10 | def get_namespace(namespace): 11 | if namespace.is_ext: 12 | return get_ext_name(namespace.ext_name) 13 | else: 14 | return "x" 15 | 16 | def get_ext_name(str): 17 | return _ext(str) 18 | 19 | _cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)') 20 | _cname_special_cases = {'DECnet':'decnet'} 21 | 22 | def _n_item(str, parts=False): 23 | ''' 24 | Does C-name conversion on a single string fragment. 25 | Uses a regexp with some hard-coded special cases. 26 | ''' 27 | if str in _cname_special_cases: 28 | return _cname_special_cases[str] 29 | else: 30 | split = _cname_re.finditer(str) 31 | name_parts = [match.group(0) for match in split] 32 | if parts: 33 | return name_parts 34 | else: 35 | return '_'.join(name_parts) 36 | 37 | _extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests'] 38 | 39 | def _ext(str): 40 | ''' 41 | Does C-name conversion on an extension name. 42 | Has some additional special cases on top of _n_item. 43 | ''' 44 | if str in _extension_special_cases: 45 | return _n_item(str).lower() 46 | else: 47 | return str.lower() 48 | 49 | def _n(list, namespace): 50 | ''' 51 | Does C-name conversion on a tuple of strings. 52 | Different behavior depending on length of tuple, extension/not extension, etc. 53 | Basically C-name converts the individual pieces, then joins with underscores. 54 | ''' 55 | if len(list) == 1: 56 | parts = list 57 | elif len(list) == 2: 58 | parts = [list[0], _n_item(list[1])] 59 | elif namespace.is_ext: 60 | parts = [list[0], _ext(list[1])] + [_n_item(i) for i in list[2:]] 61 | else: 62 | parts = [list[0]] + [_n_item(i) for i in list[1:]] 63 | return '_'.join(parts).lower() 64 | -------------------------------------------------------------------------------- /src/tests/.gitignore: -------------------------------------------------------------------------------- 1 | event 2 | iterator 3 | -------------------------------------------------------------------------------- /src/tests/Makefile: -------------------------------------------------------------------------------- 1 | include ../flags.makefile 2 | 3 | # CXX=clang 4 | CXXFLAGS+=-g 5 | # CXXFLAGS+=-Wextra 6 | # CXXFLAGS+=-ftime-report 7 | 8 | CPPSRCS=event.cpp \ 9 | requests.cpp \ 10 | iterator.cpp 11 | 12 | all: ${CPPSRCS} 13 | 14 | ${CPPSRCS}: 15 | ${CXX} ${LDFLAGS} ${CXXFLAGS} -o $(@:%.cpp=%) $@ 16 | 17 | xlib-test: xlib-test.cpp 18 | ${CXX} $(shell pkg-config --libs --cflags x11 xrandr) -o $@ $< 19 | 20 | version: 21 | 22 | clean: 23 | rm -f ${CPPSRCS:%.cpp=%} 24 | 25 | .PHONY: ${CPPSRCS} clean 26 | -------------------------------------------------------------------------------- /src/tests/README.md: -------------------------------------------------------------------------------- 1 | Just a couple of experiments to try out concepts, language features, ideas. 2 | Might or might not compile, run or crash, etc. 3 | -------------------------------------------------------------------------------- /src/tests/callable.cpp: -------------------------------------------------------------------------------- 1 | // compile with `g++ -std=c++11 test.cpp` 2 | #include 3 | 4 | #define CALLABLE(FUNCTION) callable 5 | 6 | template 7 | struct callable; 8 | 9 | template 11 | struct callable { 12 | Return operator()(Args ... args) 13 | { 14 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 15 | return Function(args ...); 16 | } 17 | }; 18 | 19 | template 20 | class one_size_fits_them_all; 21 | 22 | // A generic template 23 | template 25 | class one_size_fits_them_all 26 | { 27 | public: 28 | one_size_fits_them_all(void) 29 | { 30 | std::cerr << "generic one_size_fits_them_all" << std::endl 31 | << __PRETTY_FUNCTION__ << std::endl << std::endl; 32 | F1()(); 33 | F2()(); 34 | F3()(); 35 | std::cerr << std::endl; 36 | } 37 | }; 38 | 39 | // A specialized template 40 | template 41 | class one_size_fits_them_all 42 | { 43 | public: 44 | one_size_fits_them_all(void) 45 | { 46 | std::cerr << "specialized one_size_fits_them_all" << std::endl 47 | << __PRETTY_FUNCTION__ << std::endl << std::endl; 48 | Callable()(); 49 | std::cerr << std::endl; 50 | } 51 | }; 52 | 53 | void f1(void) 54 | { 55 | std::cerr << __PRETTY_FUNCTION__ << std::endl << std::endl; 56 | } 57 | 58 | void f2(void) 59 | { 60 | std::cerr << __PRETTY_FUNCTION__ << std::endl << std::endl; 61 | } 62 | 63 | void f3(void) 64 | { 65 | std::cerr << __PRETTY_FUNCTION__ << std::endl << std::endl; 66 | } 67 | 68 | int main(int argc, char ** argv) 69 | { 70 | // generic template 71 | auto generic = one_size_fits_them_all< 72 | int, int, int, CALLABLE(f1), CALLABLE(f2), CALLABLE(f3)>(); 73 | 74 | // specialized template 75 | auto specialized_int = one_size_fits_them_all< 76 | int, int, int, void, void, CALLABLE(f1)>(); 77 | 78 | // specialized template 79 | auto specialized_double = one_size_fits_them_all< 80 | double, int, int, void, void, CALLABLE(f3)>(); 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /src/tests/event.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../event.hpp" 4 | #include "../connection.hpp" 5 | 6 | using namespace xpp; 7 | using namespace event; 8 | 9 | xcb_window_t 10 | get_window(xcb_button_press_event_t * const e) 11 | { 12 | return e->event; 13 | } 14 | 15 | xcb_window_t 16 | get_window(xcb_motion_notify_event_t * const e) 17 | { 18 | return e->event; 19 | } 20 | 21 | namespace test { 22 | 23 | class handler : public dispatcher 24 | , public sink 25 | , public sink 26 | , public sink 27 | { 28 | public: 29 | void handle(const button::press &) 30 | { 31 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 32 | } 33 | 34 | void handle(const button::release & e) 35 | { 36 | if (XCB_BUTTON_PRESS == (e->response_type & ~0x80)) { 37 | std::cerr << __PRETTY_FUNCTION__ << " XCB_BUTTON_PRESS" << std::endl; 38 | } else { 39 | std::cerr << __PRETTY_FUNCTION__ << " XCB_BUTTON_RELEASE" << std::endl; 40 | } 41 | } 42 | 43 | void handle(const motion::notify &) 44 | { 45 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 46 | } 47 | }; 48 | 49 | class container : public direct::container { 50 | public: 51 | dispatcher * const 52 | at(const unsigned int & window) const 53 | { 54 | return m_dispatcher.at(window); 55 | } 56 | 57 | std::unordered_map m_dispatcher; 58 | }; 59 | 60 | struct foo { 61 | void bar(void) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 62 | }; 63 | 64 | class foo_container : public any::container { 65 | public: 66 | foo * const at(const unsigned int & window) 67 | { 68 | return &m_foos.at(window); 69 | } 70 | 71 | std::unordered_map m_foos; 72 | }; 73 | 74 | class foo_handler : public any::adapter { 75 | public: 76 | using adapter::adapter; 77 | 78 | void handle(foo * const f, const button::press & e) 79 | { 80 | std::cerr << __PRETTY_FUNCTION__ << " response_type: " << (int)(e->response_type & ~0x80) << std::endl; 81 | f->bar(); 82 | } 83 | }; 84 | 85 | }; // namespace test 86 | 87 | int main(int argc, char ** argv) 88 | { 89 | connection c(""); 90 | source source(c); 91 | 92 | auto tree = c.query_tree(c.root()); 93 | 94 | test::handler handler; 95 | test::container container; 96 | 97 | test::foo_container foo_container; 98 | test::foo_handler foo_handler(source, foo_container); 99 | 100 | for (auto & window : tree.children()) { 101 | *(c.grab_pointer(false, window, 102 | XCB_EVENT_MASK_BUTTON_PRESS 103 | | XCB_EVENT_MASK_BUTTON_RELEASE 104 | | XCB_EVENT_MASK_POINTER_MOTION, 105 | XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, 106 | XCB_NONE, XCB_NONE, XCB_TIME_CURRENT_TIME)); 107 | 108 | container.m_dispatcher[window] = &handler; 109 | foo_container.m_foos[window] = test::foo(); 110 | } 111 | 112 | dispatcher * dispatcher[] = 113 | { new direct::adapter(source, container) 114 | , new direct::adapter(source, container) 115 | , new direct::adapter(source, container) 116 | }; 117 | 118 | source.run(); 119 | 120 | for (auto * d : dispatcher) { 121 | delete d; 122 | } 123 | 124 | return EXIT_SUCCESS; 125 | } 126 | -------------------------------------------------------------------------------- /src/tests/iterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../connection.hpp" 4 | 5 | class test { 6 | public: 7 | 8 | template 9 | class iterator { 10 | public: 11 | iterator(Data * const data, std::size_t index) 12 | : m_data(data), m_index(index) 13 | {} 14 | 15 | bool operator==(const iterator & other) 16 | { 17 | return m_index == other.m_index; 18 | } 19 | 20 | bool operator!=(const iterator & other) 21 | { 22 | return ! (*this == other); 23 | } 24 | 25 | const Data & operator*(void) 26 | { 27 | return m_data[m_index]; 28 | } 29 | 30 | // prefix 31 | iterator & operator++(void) 32 | { 33 | ++m_index; 34 | return *this; 35 | } 36 | 37 | // postfix 38 | iterator operator++(int) 39 | { 40 | auto copy = *this; 41 | ++(*this); 42 | return copy; 43 | } 44 | 45 | // prefix 46 | iterator & operator--(void) 47 | { 48 | --m_index; 49 | return *this; 50 | } 51 | 52 | // postfix 53 | iterator operator--(int) 54 | { 55 | auto copy = *this; 56 | --(*this); 57 | return copy; 58 | } 59 | 60 | private: 61 | Data * const m_data; 62 | std::size_t m_index = 0; 63 | }; 64 | 65 | 66 | template 67 | iterator begin(void) 68 | { 69 | throw "This must not happen!"; 70 | } 71 | 72 | template 73 | iterator end(void) 74 | { 75 | throw "This must not happen!"; 76 | } 77 | 78 | // private: 79 | std::vector m_ints; 80 | std::vector m_doubles; 81 | 82 | }; 83 | 84 | template<> 85 | test::iterator test::begin(void) 86 | { 87 | return iterator(m_ints.data(), 0); 88 | } 89 | 90 | template<> 91 | test::iterator test::begin(void) 92 | { 93 | return iterator(m_doubles.data(), 0); 94 | } 95 | 96 | template<> 97 | test::iterator test::end(void) 98 | { 99 | return iterator(m_ints.data(), m_ints.size()); 100 | } 101 | 102 | template<> 103 | test::iterator test::end(void) 104 | { 105 | return iterator(m_doubles.data(), m_ints.size()); 106 | } 107 | 108 | int main(int argc, char ** argv) 109 | { 110 | xpp::connection c(""); 111 | 112 | auto tree = c.query_tree(c.root()); 113 | 114 | std::cerr << "#windows (children_len): " << tree->children_len << std::endl; 115 | std::cerr << "#windows (length): " << tree->length << std::endl; 116 | 117 | std::cerr << std::hex; 118 | for (auto & window : tree.children()) { 119 | std::cerr << "0x" << window << "; "; 120 | } 121 | std::cerr << std::dec << std::endl;; 122 | 123 | std::cerr << std::hex; 124 | for (auto it = tree.children().begin(); it != tree.children().end(); ++it) { 125 | std::cerr << "0x" << *it << "; "; 126 | } 127 | std::cerr << std::dec << std::endl;; 128 | 129 | std::cerr << std::hex; 130 | auto it = tree.children().begin(); 131 | std::cerr << "it : " << *it << std::endl; 132 | std::cerr << "++it: " << *(++it) << std::endl; 133 | std::cerr << "it : " << *it << std::endl; 134 | std::cerr << "it++: " << *(it++) << std::endl; 135 | std::cerr << "it : " << *it << std::endl; 136 | std::cerr << "++it: " << *(++it) << std::endl; 137 | std::cerr << "it : " << *it << std::endl; 138 | std::cerr << "--it: " << *(--it) << std::endl; 139 | std::cerr << "it : " << *it << std::endl; 140 | std::cerr << "it--: " << *(it--) << std::endl; 141 | std::cerr << "it : " << *it << std::endl; 142 | std::cerr << std::dec << std::endl;; 143 | 144 | auto atom = c.intern_atom(false, "_NET_CLIENT_LIST_STACKING"); 145 | auto properties = c.get_property( 146 | false, c.root(), atom->atom, XCB_ATOM_WINDOW, 0, UINT32_MAX); 147 | 148 | std::cerr << std::hex; 149 | for (auto & window : properties) { 150 | std::cerr << "0x" << window << "; "; 151 | } 152 | std::cerr << std::dec << std::endl;; 153 | 154 | return EXIT_SUCCESS; 155 | } 156 | -------------------------------------------------------------------------------- /src/tests/resource.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../xpp.hpp" 4 | #include "../proto/randr.hpp" 5 | #include "../proto/damage.hpp" 6 | #include "../proto/render.hpp" 7 | 8 | #include 9 | #include 10 | #include // XC_cross 11 | 12 | namespace x { 13 | typedef xpp::connection< 14 | // xpp::randr::extension, 15 | // xpp::damage::extension, 16 | // xpp::render::extension 17 | > 18 | connection; 19 | 20 | typedef xpp::event::registry 24 | > 25 | registry; 26 | 27 | typedef xpp::font font; 28 | typedef xpp::cursor cursor; 29 | typedef xpp::window window; 30 | typedef xpp::window xcb_window; 31 | 32 | typedef xpp::x::event::key_press key_press; 33 | typedef xpp::x::event::key_release key_release; 34 | typedef xpp::x::event::button_press button_press; 35 | typedef xpp::randr::event::notify randr_notify; 36 | typedef xpp::randr::event::screen_change_notify randr_screen_change_notify; 37 | typedef xpp::damage::event::notify damage_notify; 38 | }; 39 | 40 | int main(int argc, char ** argv) 41 | { 42 | x::connection connection; 43 | xcb_font_t font = 0; 44 | auto cursor_1 = x::cursor(connection, 0); 45 | auto cursor_2 = x::cursor::create_glyph(connection, font, font, 46 | XC_cross, XC_cross + 1, 0, 0, 0, 0xffff, 0xffff, 0xffff); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /src/tests/sizeof.cpp: -------------------------------------------------------------------------------- 1 | // compile with `g++ -std=c++11 test.cpp` 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace test1 { 9 | 10 | template 11 | struct interface { 12 | static std::size_t size_of(void) 13 | { 14 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 15 | return sizeof(T); 16 | } 17 | }; 18 | 19 | template<> 20 | struct interface { 21 | static std::size_t size_of(void) 22 | { 23 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 24 | return sizeof(char); 25 | } 26 | }; 27 | 28 | template 29 | struct A : public interface { 30 | A(void) 31 | { 32 | std::cerr << __PRETTY_FUNCTION__ << " size_of(): " 33 | << this->size_of() << std::endl; 34 | } 35 | 36 | static std::size_t size_of(void) 37 | { 38 | std::cerr << "YOLOLOL" << std::endl; 39 | return 0; 40 | } 41 | }; 42 | 43 | // template 44 | struct B : public interface { 45 | B(void) 46 | { 47 | std::cerr << __PRETTY_FUNCTION__ << " size_of(): " 48 | << this->size_of() << std::endl; 49 | } 50 | }; 51 | 52 | // template 53 | struct C : public interface { 54 | C(void) 55 | { 56 | std::cerr << __PRETTY_FUNCTION__ << " size_of(): " 57 | << this->size_of() << std::endl; 58 | } 59 | }; 60 | 61 | int main(int argc, char ** argv) 62 | { 63 | test1::A t1_1; 64 | std::cerr << std::endl; 65 | test1::A t1_2; 66 | std::cerr << std::endl; 67 | test1::A t1_3; 68 | std::cerr << std::endl; 69 | test1::A t1_4; 70 | std::cerr << std::endl; 71 | test1::A t1_5; 72 | std::cerr << std::endl; 73 | 74 | test1::B t2_1; 75 | std::cerr << std::endl; 76 | 77 | test1::C t3_1; 78 | std::cerr << std::endl; 79 | 80 | return 0; 81 | } 82 | 83 | }; 84 | 85 | namespace test2 { 86 | 87 | struct interface { 88 | static void test(void); 89 | }; 90 | 91 | struct A : public interface { 92 | static void test(void) 93 | { 94 | std::cerr << __PRETTY_FUNCTION__ << " (A::test)" << std::endl; 95 | } 96 | A(void) 97 | { 98 | test(); 99 | } 100 | }; 101 | 102 | struct B : public interface { 103 | static void test(void) 104 | { 105 | std::cerr << __PRETTY_FUNCTION__ << " (B::test)" << std::endl; 106 | } 107 | B(void) 108 | { 109 | test(); 110 | } 111 | }; 112 | 113 | void test(const interface & i) 114 | { 115 | A::test(); 116 | B::test(); 117 | // decltype(i)::test(); 118 | } 119 | 120 | int main(int argc, char ** argv) 121 | { 122 | test2::A a; 123 | test2::B b; 124 | test2::test(a); 125 | // test2::test(); 126 | 127 | return 0; 128 | } 129 | 130 | }; 131 | 132 | namespace test3 { 133 | 134 | template 135 | struct Base { 136 | T t; 137 | }; 138 | 139 | template 140 | struct select_type; 141 | 142 | template<> 143 | struct select_type<1> { 144 | Base base; 145 | }; 146 | 147 | template<> 148 | struct select_type<2> { 149 | Base base; 150 | }; 151 | 152 | int main(int argc, char ** argv) 153 | { 154 | constexpr int i = 0; 155 | test3::select_type<1> st_1; 156 | test3::select_type<2> st_2; 157 | 158 | return 0; 159 | } 160 | 161 | }; 162 | 163 | namespace test4 { 164 | 165 | template 166 | struct i { 167 | virtual bool f(T) = 0; 168 | }; 169 | 170 | namespace a { 171 | struct a : public i { 172 | bool f(int i) 173 | { 174 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 175 | return i == m_i; 176 | } 177 | int m_i = 0; 178 | }; 179 | }; 180 | 181 | namespace b { 182 | struct b : public i { 183 | bool f(int i) 184 | { 185 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 186 | return i == m_i; 187 | } 188 | int m_i = 1; 189 | }; 190 | }; 191 | 192 | namespace c { 193 | struct c : public i { 194 | bool f(int i) 195 | { 196 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 197 | return i == m_i; 198 | } 199 | int m_i = 2; 200 | }; 201 | }; 202 | 203 | template 204 | struct z : public IS ... { 205 | 206 | // template 207 | void 208 | run(int i) 209 | { 210 | std::cerr << __PRETTY_FUNCTION__ << " with i = " << i << std::endl; 211 | f(i, static_cast(this) ...); 212 | } 213 | 214 | template 215 | void 216 | f(int v, I * i, ISS ... is) 217 | { 218 | if (! i->f(v)) { 219 | f(v, is ...); 220 | } else { 221 | std::cerr << "We've got a winner!" << std::endl; 222 | } 223 | } 224 | 225 | template 226 | void 227 | f(int v, I * i) 228 | { 229 | i->f(v); 230 | } 231 | 232 | }; 233 | 234 | int main(int argc, char ** argv) 235 | { 236 | test4::z z; 237 | for (auto i : { 0, 1, 2, 3 }) { 238 | z.run(i); 239 | } 240 | return 0; 241 | } 242 | 243 | }; 244 | 245 | namespace test5 { 246 | 247 | struct pod_generic { 248 | int id; 249 | int m_int; 250 | }; 251 | 252 | struct pod_int { 253 | int id = 0; 254 | int m_int; 255 | }; 256 | 257 | struct pod_double { 258 | int id = 1; 259 | double m_double; 260 | }; 261 | 262 | struct pod_string { 263 | int id = 2; 264 | std::string m_string; 265 | }; 266 | 267 | template 268 | struct my_pod_wrapper { 269 | static const int opcode = OpCode; 270 | }; 271 | 272 | struct my_pod_int_wrapper : public my_pod_wrapper<0> { 273 | my_pod_int_wrapper(pod_generic * pg) 274 | : m_pi((pod_int *)pg) {} 275 | pod_int * m_pi; 276 | }; 277 | 278 | struct my_pod_double_wrapper : public my_pod_wrapper<1> { 279 | my_pod_double_wrapper(pod_generic * pg) 280 | : m_pd((pod_double *)pg) {} 281 | pod_double * m_pd; 282 | }; 283 | 284 | struct my_pod_string_wrapper : public my_pod_wrapper<2> { 285 | my_pod_string_wrapper(pod_generic * pg) 286 | : m_ps((pod_string *)pg) {} 287 | pod_string * m_ps; 288 | }; 289 | 290 | class dispatcher { 291 | public: 292 | virtual ~dispatcher(void) {} 293 | template void dispatch(const E & e); 294 | }; 295 | 296 | template 297 | class sink; 298 | 299 | template 300 | class sink : virtual public dispatcher { 301 | public: 302 | virtual void handle(const E & e) = 0; 303 | }; 304 | 305 | template 306 | class sink 307 | : virtual public sink 308 | , virtual public sink ... 309 | {}; 310 | 311 | template 312 | void dispatcher::dispatch(const E & e) 313 | { 314 | dynamic_cast *>(this)->handle(e); 315 | } 316 | 317 | template 318 | class pod_dispatcher { 319 | public: 320 | template 321 | bool 322 | operator()(pod_generic * pg, const Dispatcher & D) const 323 | { 324 | // std::cerr << __PRETTY_FUNCTION__ << std::endl; 325 | std::cerr << "POD_DISPATCHER<" << ExtensionId << ">" << std::endl; 326 | switch (pg->id) { 327 | case 0: 328 | // std::cerr << "dispatch with my_pod_int_wrapper" << std::endl; 329 | D(my_pod_int_wrapper(pg)); 330 | return true; 331 | 332 | case 1: 333 | // std::cerr << "dispatch with my_pod_double_wrapper" << std::endl; 334 | D(my_pod_double_wrapper(pg)); 335 | return true; 336 | 337 | case 2: 338 | // std::cerr << "dispatch with my_pod_string_wrapper" << std::endl; 339 | D(my_pod_string_wrapper(pg)); 340 | return true; 341 | }; 342 | 343 | return false; 344 | } 345 | }; 346 | 347 | template<> 348 | class pod_dispatcher<1> { 349 | public: 350 | template 351 | bool 352 | operator()(pod_generic * pg, const Dispatcher & D) const 353 | { 354 | std::cerr << "POD_DISPATCHER<1>" << std::endl; 355 | switch (pg->id) { 356 | case 0: 357 | // std::cerr << "dispatch with my_pod_int_wrapper" << std::endl; 358 | D(my_pod_int_wrapper(pg)); 359 | return true; 360 | 361 | case 1: 362 | // std::cerr << "dispatch with my_pod_double_wrapper" << std::endl; 363 | D(my_pod_double_wrapper(pg)); 364 | return true; 365 | 366 | case 2: 367 | // std::cerr << "dispatch with my_pod_string_wrapper" << std::endl; 368 | D(my_pod_string_wrapper(pg)); 369 | return true; 370 | }; 371 | 372 | return false; 373 | } 374 | }; 375 | 376 | class a : public sink 379 | { 380 | public: 381 | virtual void handle(const my_pod_int_wrapper &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 382 | virtual void handle(const my_pod_double_wrapper &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 383 | virtual void handle(const my_pod_string_wrapper &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 384 | }; 385 | 386 | class b : public sink 388 | { 389 | public: 390 | virtual void handle(const my_pod_string_wrapper &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 391 | virtual void handle(const my_pod_double_wrapper &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 392 | }; 393 | 394 | class c : public sink 395 | { 396 | public: 397 | virtual void handle(const my_pod_double_wrapper &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 398 | }; 399 | 400 | template 401 | struct handler_registry { 402 | 403 | template 404 | bool 405 | dispatch(pod_generic * pg) const 406 | { 407 | std::cerr << "RecursiveDispatchEnd_EvenBetter" << std::endl; 408 | return D()(pg, *this); 409 | } 410 | 411 | template 412 | bool 413 | dispatch(pod_generic * pg) const 414 | { 415 | std::cerr << "BigFatDispatch_ManFeelsGood" << std::endl; 416 | D1()(pg, *this); 417 | return dispatch(pg); 418 | } 419 | 420 | bool 421 | dispatch(pod_generic * pg) const 422 | { 423 | std::cerr << "InitialDispatch_JustAbitWeiry" << std::endl; 424 | return dispatch(pg); 425 | } 426 | 427 | template 428 | void 429 | operator()(const Event & e) const 430 | { 431 | try { 432 | for (auto & item : m_dispatcher.at(Event::opcode)) { 433 | item.second->dispatch(e); 434 | } 435 | } catch (...) {} 436 | } 437 | 438 | template 439 | void 440 | attach(sink * s) 441 | { 442 | attach(Event1::opcode, s); 443 | attach((sink *)s); 444 | } 445 | 446 | template 447 | void 448 | attach(sink * s) 449 | { 450 | attach(Event::opcode, s); 451 | } 452 | 453 | void attach(unsigned int opcode, dispatcher * d) 454 | { 455 | m_dispatcher[opcode].emplace(0, d); 456 | } 457 | 458 | std::unordered_map> m_dispatcher; 460 | }; 461 | 462 | template 463 | void foo(int i, I j) {} 464 | 465 | int main(int argc, char ** argv) 466 | { 467 | int i = 42; 468 | std::string s = "42"; 469 | 470 | pod_int pi; 471 | pod_double pd; 472 | pod_string ps; 473 | 474 | test5::a a; 475 | test5::b b; 476 | test5::c c; 477 | 478 | handler_registry, 479 | pod_dispatcher<1>, 480 | pod_dispatcher<2>> registry; 481 | 482 | registry.attach(&a); 483 | registry.attach(&b); 484 | registry.attach(&c); 485 | 486 | registry.dispatch((test5::pod_generic *)&pi); 487 | registry.dispatch((test5::pod_generic *)&ps); 488 | registry.dispatch((test5::pod_generic *)&pd); 489 | 490 | return 0; 491 | } 492 | 493 | }; 494 | 495 | namespace test6 { 496 | template 497 | struct foo {}; 498 | 499 | template < typename... Types1, template class T 500 | , typename... Types2, template class V 501 | , typename U > 502 | void 503 | bar(const T&, const V&, const U& u) 504 | { 505 | std::cout << sizeof...(Types1) << std::endl; 506 | std::cout << sizeof...(Types2) << std::endl; 507 | std::cout << u << std::endl; 508 | } 509 | 510 | int main(int argc, char ** argv) 511 | { 512 | foo f1; 513 | foo f2; 514 | bar(f1, f2, 9); 515 | return 0; 516 | } 517 | }; 518 | 519 | namespace test7 { 520 | 521 | static constexpr std::size_t * my_ext_1 = nullptr; 522 | static constexpr std::size_t * my_ext_2 = nullptr; 523 | static constexpr std::size_t * my_ext_3 = nullptr; 524 | static constexpr std::size_t * my_ext_4 = nullptr; 525 | 526 | // static const std::size_t id_4_0 = reinterpret_cast(&my_ext_4 + 0); 527 | // static const std::size_t id_4_1 = reinterpret_cast(&my_ext_4 + 1); 528 | // static const std::size_t id_4_2 = reinterpret_cast(&my_ext_4 + 2); 529 | 530 | namespace p1 { 531 | template 532 | struct ext {}; 533 | 534 | template<> 535 | struct ext { 536 | void call(void) const { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 537 | }; 538 | }; 539 | 540 | namespace p2 { 541 | template 542 | struct ext {}; 543 | 544 | template<> 545 | struct ext { 546 | void call(void) const { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 547 | }; 548 | }; 549 | 550 | namespace p3 { 551 | template 552 | struct ext {}; 553 | 554 | template<> 555 | struct ext { 556 | void call(void) const { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 557 | }; 558 | }; 559 | 560 | struct proto_1 { 561 | typedef p1::ext ext; 562 | template 563 | void dispatch(const Handler & h, const Event & e) 564 | { 565 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 566 | e.call(static_cast(h)); 567 | } 568 | }; 569 | 570 | struct proto_2 { 571 | typedef p2::ext ext; 572 | template 573 | void dispatch(const Handler & h, const Event & e) 574 | { 575 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 576 | e.call(static_cast(h)); 577 | } 578 | }; 579 | 580 | struct proto_3 { 581 | typedef p3::ext ext; 582 | template 583 | void dispatch(const Handler & h, const Event & e) 584 | { 585 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 586 | e.call(static_cast(h)); 587 | } 588 | }; 589 | 590 | struct event_1 { 591 | typedef p1::ext ext; 592 | typedef proto_1 proto; 593 | // void call(void) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 594 | void call(const ext & e) const { std::cerr << __PRETTY_FUNCTION__ << std::endl; e.call(); } 595 | }; 596 | 597 | struct event_2 { 598 | typedef p2::ext ext; 599 | typedef proto_2 proto; 600 | // void call(void) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 601 | void call(const ext & e) const { std::cerr << __PRETTY_FUNCTION__ << std::endl; e.call(); } 602 | }; 603 | 604 | struct event_3 { 605 | typedef p3::ext ext; 606 | typedef proto_3 proto; 607 | // void call(void) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 608 | void call(const ext & e) const { std::cerr << __PRETTY_FUNCTION__ << std::endl; e.call(); } 609 | }; 610 | 611 | struct pod_event_1 { 612 | const int id = 1; 613 | }; 614 | 615 | struct pod_event_2 { 616 | const int id = 2; 617 | }; 618 | 619 | struct pod_event_3 { 620 | const int id = 3; 621 | }; 622 | 623 | template 624 | struct proto 625 | : public Protos ... 626 | , public Protos::ext ... 627 | { 628 | 629 | template 630 | void run(const Event & event) 631 | { 632 | static_cast(this)->dispatch(*this, event); 633 | } 634 | 635 | }; 636 | 637 | int main(int argc, char ** argv) 638 | { 639 | std::cerr << "my_ext_1: " << my_ext_1 << std::endl; 640 | std::cerr << "my_ext_2: " << my_ext_2 << std::endl; 641 | std::cerr << "my_ext_3: " << my_ext_3 << std::endl; 642 | 643 | proto p; 644 | 645 | event_1 e_1; 646 | event_2 e_2; 647 | event_3 e_3; 648 | 649 | p.run(e_1); 650 | p.run(e_2); 651 | p.run(e_3); 652 | 653 | return 0; 654 | } 655 | 656 | }; // namespace test7 657 | 658 | namespace test8 { 659 | 660 | struct a { 661 | void operator()(void) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 662 | }; 663 | 664 | struct b { 665 | void operator()(void) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 666 | }; 667 | 668 | struct c { 669 | void operator()(void) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 670 | }; 671 | 672 | struct wrap_hull 673 | { 674 | virtual void do_cool_stuff(void) = 0; 675 | }; 676 | 677 | template 678 | struct wrap 679 | : public wrap_hull 680 | , public Args ... 681 | { 682 | void do_cool_stuff(void) { std::cerr << __PRETTY_FUNCTION__ << std::endl; } 683 | }; 684 | 685 | template 686 | struct test : public Args ... 687 | { 688 | void trigger(void) 689 | { 690 | run(); 691 | } 692 | 693 | template 694 | void run(void) 695 | { 696 | run(); 697 | run(); 698 | } 699 | 700 | template 701 | void run(void) 702 | { 703 | Arg()(); 704 | } 705 | 706 | template 707 | void 708 | insert(wrap * w) 709 | { 710 | insert( 711 | reinterpret_cast *>(w), 712 | reinterpret_cast *>(w) ...); 713 | } 714 | 715 | template 716 | void 717 | insert(wrap * w, wrap * ws ...) 718 | { 719 | insert(w); 720 | insert( 721 | reinterpret_cast *>(w), 722 | reinterpret_cast *>(w) ...); 723 | } 724 | 725 | template 726 | void 727 | insert(wrap_hull * wh) 728 | { 729 | m_wraps.push_back(wh); 730 | } 731 | 732 | void call_objects(void) 733 | { 734 | for (auto * wh : m_wraps) { 735 | wh->do_cool_stuff(); 736 | } 737 | } 738 | 739 | std::vector m_wraps; 740 | }; 741 | 742 | int main(int argc, char ** argv) 743 | { 744 | struct test t; 745 | t.trigger(); 746 | 747 | struct wrap w; 748 | t.insert(&w); 749 | 750 | t.call_objects(); 751 | 752 | return 0; 753 | } 754 | 755 | }; // namespace test8 756 | 757 | int main(int argc, char ** argv) 758 | { 759 | // return test1::main(argc, argv); 760 | // return test2::main(argc, argv); 761 | // return test3::main(argc, argv); 762 | // return test4::main(argc, argv); 763 | // return test5::main(argc, argv); 764 | // return test6::main(argc, argv); 765 | // return test7::main(argc, argv); 766 | return test8::main(argc, argv); 767 | } 768 | -------------------------------------------------------------------------------- /src/tests/template.cpp: -------------------------------------------------------------------------------- 1 | // compile with `g++ -std=c++11 test.cpp` 2 | #include 3 | 4 | #define CALLABLE(FUNCTION) callable 5 | 6 | template 7 | struct callable; 8 | 9 | template 11 | struct callable { 12 | Return operator()(Args ... args) 13 | { 14 | std::cerr << __PRETTY_FUNCTION__ << std::endl; 15 | return Function(args ...); 16 | } 17 | }; 18 | 19 | template 20 | class one_size_fits_them_all; 21 | 22 | // A generic template 23 | template 25 | class one_size_fits_them_all 26 | { 27 | public: 28 | one_size_fits_them_all(void) 29 | { 30 | std::cerr << "generic one_size_fits_them_all" << std::endl 31 | << __PRETTY_FUNCTION__ << std::endl << std::endl; 32 | F1()(); 33 | F2()(); 34 | F3()(); 35 | std::cerr << std::endl; 36 | } 37 | }; 38 | 39 | // A specialized template 40 | template 41 | class one_size_fits_them_all 42 | { 43 | public: 44 | one_size_fits_them_all(void) 45 | { 46 | std::cerr << "specialized one_size_fits_them_all" << std::endl 47 | << __PRETTY_FUNCTION__ << std::endl << std::endl; 48 | Callable()(); 49 | std::cerr << std::endl; 50 | } 51 | }; 52 | 53 | void f1(void) 54 | { 55 | std::cerr << __PRETTY_FUNCTION__ << std::endl << std::endl; 56 | } 57 | 58 | void f2(void) 59 | { 60 | std::cerr << __PRETTY_FUNCTION__ << std::endl << std::endl; 61 | } 62 | 63 | void f3(void) 64 | { 65 | std::cerr << __PRETTY_FUNCTION__ << std::endl << std::endl; 66 | } 67 | 68 | template 69 | struct interface { 70 | static std::size_t size_of(void) { return sizeof(T); } 71 | }; 72 | 73 | template 74 | struct test : public interface { 75 | test(void) 76 | { 77 | std::cerr << __PRETTY_FUNCTION__ << " size_of(): " << this->size_of() << std::endl; 78 | } 79 | }; 80 | 81 | int main(int argc, char ** argv) 82 | { 83 | // generic template 84 | auto generic = one_size_fits_them_all< 85 | int, int, int, CALLABLE(f1), CALLABLE(f2), CALLABLE(f3)>(); 86 | 87 | // specialized template 88 | auto specialized_int = one_size_fits_them_all< 89 | int, int, int, void, void, CALLABLE(f1)>(); 90 | 91 | // specialized template 92 | auto specialized_double = one_size_fits_them_all< 93 | double, int, int, void, void, CALLABLE(f3)>(); 94 | 95 | test t1; 96 | test t2; 97 | test t3; 98 | test t4; 99 | 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /src/tests/xlib-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | int main(int argc, char ** argv) 9 | { 10 | Display * dpy = XOpenDisplay(NULL); 11 | Window root = DefaultRootWindow(dpy); 12 | 13 | XRRScreenConfiguration * screen_cfg = XRRGetScreenInfo(dpy, root); 14 | std::cerr << "rate: " << XRRConfigCurrentRate(screen_cfg) << std::endl; 15 | 16 | for (int nsizes = 0; nsizes < 16; ++nsizes) { 17 | int nrates = 0; 18 | short * rates = XRRConfigRates(screen_cfg, nsizes, &nrates); 19 | std::cerr << "nrates: " << nrates << std::endl; 20 | for (int i = 0; i < nrates; ++i) { 21 | std::cerr << "rate: " << rates[i] << std::endl; 22 | } 23 | } 24 | 25 | int nhosts = 0; 26 | int state = 0; 27 | XHostAddress * host_addresses = XListHosts(dpy, &nhosts, &state); 28 | for (int i = 0; i < nhosts; ++i) { 29 | std::cerr << "address: " << host_addresses[i].address << std::endl; 30 | } 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/tests/xlib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | int main(int argc, char ** argv) 9 | { 10 | Display * dpy = XOpenDisplay(NULL); 11 | Window root = DefaultRootWindow(dpy); 12 | 13 | XRRScreenConfiguration * screen_cfg = XRRGetScreenInfo(dpy, root); 14 | std::cerr << "rate: " << XRRConfigCurrentRate(screen_cfg) << std::endl; 15 | 16 | int nrates = 0; 17 | short * rates = XRRConfigRates(screen_cfg, 10, &nrates); 18 | std::cerr << "nrates: " << nrates << std::endl; 19 | for (int i = 0; i < nrates; ++i) { 20 | std::cerr << "rate: " << rates[i] << std::endl; 21 | } 22 | 23 | int nhosts = 0; 24 | XHostAddress * host_addresses = XListHosts(dpy, &nhosts, True); 25 | for (int i = 0; i < nhosts; ++i) { 26 | std::cerr << "address: " << host_addresses[i].address << std::endl; 27 | } 28 | 29 | return EXIT_SUCCESS; 30 | } 31 | -------------------------------------------------------------------------------- /src/valueparam.hpp: -------------------------------------------------------------------------------- 1 | #ifndef X_VALUEPARAM_HPP 2 | #define X_VALUEPARAM_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace xpp { 8 | 9 | class valueparam { 10 | public: 11 | valueparam & 12 | set(const uint32_t & bit, const uint32_t & value) 13 | { 14 | m_has_changed = true; 15 | m_values_map[bit] = value; 16 | return *this; 17 | } 18 | 19 | uint32_t 20 | mask(void) 21 | { 22 | return m_mask; 23 | } 24 | 25 | uint32_t * const 26 | values(void) 27 | { 28 | if (m_has_changed) { 29 | m_values.clear(); 30 | } 31 | 32 | for (auto & item : m_values_map) { 33 | m_values.push_back(item.second); 34 | } 35 | 36 | m_has_changed = false; 37 | 38 | return m_values.data(); 39 | } 40 | 41 | private: 42 | bool m_has_changed = true; 43 | uint32_t m_mask = 0; 44 | std::vector m_values; 45 | std::map m_values_map; 46 | }; 47 | 48 | }; // namespace xpp 49 | 50 | #endif // X_VALUEPARAM_HPP 51 | -------------------------------------------------------------------------------- /src/window.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_WINDOW_HPP 2 | #define XPP_WINDOW_HPP 3 | 4 | #include "proto/x.hpp" 5 | #include "generic/resource.hpp" 6 | 7 | namespace xpp { 8 | 9 | template class ... Interfaces> 10 | class window 11 | : public xpp::generic::resource 13 | { 14 | protected: 15 | using base = xpp::generic::resource; 17 | 18 | template 19 | window(C && c, Create && create, Destroy && destroy) 20 | : base(base::make(std::forward(c), 21 | std::forward(create), 22 | std::forward(destroy))) 23 | {} 24 | 25 | public: 26 | using base::base; 27 | using base::operator=; 28 | 29 | template 30 | static 31 | window 32 | create(C && c, uint8_t depth, xcb_window_t parent, 33 | int16_t x, int16_t y, uint16_t width, uint16_t height, 34 | uint16_t border_width, 35 | uint16_t _class, xcb_visualid_t visual, 36 | uint32_t value_mask, const uint32_t * value_list) 37 | { 38 | return window( 39 | std::forward(c), 40 | [&](const Connection & c, const xcb_window_t & window) 41 | { 42 | xpp::x::create_window(c, depth, window, parent, 43 | x, y, width, height, border_width, 44 | _class, visual, 45 | value_mask, value_list); 46 | }, 47 | [&](const Connection & c, const xcb_window_t & window) 48 | { 49 | xpp::x::destroy_window(c, window); 50 | }); 51 | } 52 | 53 | template 54 | static 55 | window 56 | create_checked(C && c, uint8_t depth, xcb_window_t parent, 57 | int16_t x, int16_t y, uint16_t width, uint16_t height, 58 | uint16_t border_width, 59 | uint16_t _class, xcb_visualid_t visual, 60 | uint32_t value_mask, const uint32_t * value_list) 61 | { 62 | return window( 63 | std::forward(c), 64 | [&](const Connection & c, const xcb_window_t & window) 65 | { 66 | xpp::x::create_window_checked(c, depth, window, parent, 67 | x, y, width, height, border_width, 68 | _class, visual, 69 | value_mask, value_list); 70 | }, 71 | [&](const Connection & c, const xcb_window_t & window) 72 | { 73 | xpp::x::destroy_window_checked(c, window); 74 | }); 75 | } 76 | }; 77 | 78 | namespace generic { 79 | 80 | template class ... Interfaces> 81 | struct traits> 82 | { 83 | typedef xcb_window_t type; 84 | }; 85 | 86 | }; // namespace generic 87 | 88 | }; // namespace xpp 89 | 90 | #endif // XPP_WINDOW_HPP 91 | -------------------------------------------------------------------------------- /src/xpp.hpp: -------------------------------------------------------------------------------- 1 | #ifndef XPP_HPP 2 | #define XPP_HPP 3 | 4 | #include "generic.hpp" 5 | 6 | #include "atom.hpp" 7 | #include "colormap.hpp" 8 | #include "cursor.hpp" 9 | #include "drawable.hpp" 10 | #include "font.hpp" 11 | #include "fontable.hpp" 12 | #include "gcontext.hpp" 13 | #include "pixmap.hpp" 14 | #include "window.hpp" 15 | 16 | #include "event.hpp" 17 | #include "connection.hpp" 18 | 19 | #endif // XPP_HPP 20 | --------------------------------------------------------------------------------