1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
# Introduction
Wayland is an object oriented display protocol, which features request
and events. Requests can be seen as method calls on certain objects,
whereas events can be seen as signals of an object. This makes the
Wayland protocol a perfect candidate for a C++ binding.
The goal of this library is to create such a C++ binding for Wayland
using the most modern C++ technology currently available, providing
an easy to use C++ API to Wayland.
# Requirements
To build this library, a recent version of cmake is required. Furthermore,
a recent C++ Compiler with C++11 support, such as GCC or clang, is required.
Also, pugixml is required to build the XML protocol scanner. Apart from the
Wayland libraries, there are no further library dependencies.
The documentation is autogenerated using Doxygen, therefore doxygen as
well as graphviz is required.
# Building
## Library
To build the library, `cmake ..` needs to executed in a newly created
`build` directory in the root directory of the repository, followed
by a `make`. After that, `make install` will install the library.
There are several CMake variables that can be set in order to
customise the build and install process:
CMake Variable | Effect
---------------------------- | ------
`CMAKE_CXX_COMPILER` | C++ compiler to use
`CMAKE_CXX_FLAGS` | Additional flags for the C++ compiler
`CMAKE_INSTALL_PREFIX` | Prefix folder, under which everything is installed
`CMAKE_INSTALL_LIBDIR` | Library folder relative to the prefix
`CMAKE_INSTALL_INCLUDEDIR` | Header folder relative to the prefix
`CMAKE_INSTALL_BINDIR` | Binary folder relative to the prefix
`CMAKE_INSTALL_DATAROOTDIR` | Shared folder relative to the prefix
`CMAKE_INSTALL_DOCDIR` | Documentation folder relative to the prefix
`CMAKE_INSTALL_MANDIR` | Manpage folder relative to the prefix
`BUILD_SCANNER` | Whether to build the scanner
`BUILD_LIBRARIES` | Whether to build the libraries
`BUILD_DOCUMENTATION` | Whether to build the documentation
`BUILD_EXAMPLES` | Whether to build the examples
`INSTALL_UNSTABLE_PROTOCOLS` | Whether to install the unstable protocols
The installation root can also be changed using the environment variable
`DESTDIR` when using `make install`.
## Documentation
If the requirements are met, the documentation will normally be built
automatically. HTML pages, LaTeX source files as well as manpages are generated.
To build the documentation manually, `doxygen` needs to be executed
in the root directory of the repository. The resulting documentation
can then be found in the `doc` directory. The required Doxyfile is
available after the library has been built. The documentaion is also
online availabe [here](https://nilsbrause.github.io/waylandpp_docs/).
## Example programs
To build the example programs the `BUILD_EXAMPLES` option needs to be enabled
during the build. The resulting binaries will be put under the `example`
directory inside the build directory. They can be run directly without
installing the library first.
To build the example programs manually, `make` can executed in
the example directory after the library has been built and installed.
# Usage
In the following, it is assumed that the reader is familiar with
basic Wayland concepts and at least version 11 of the C++
programming language.
## Clients
Each interface is represented by a class. E.g. the `wl_registry`
interface is represented by the `registry_t` class.
An instance of a class is a wrapper for a Wayland object (a `wl_proxy`
pointer). If a copy is made of a particualr instance, both instances
refer to the same Wayland object. The underlying Wayland object is
destroyed once there are no copies of this object left. Only a few
classes are non-copyable, namely `display_t` and `egl_window_t`.
There are also special rules for proxy wrappers and the use of
foreigen objects. Refer to the documentation for more details.
A request to an object of a specific interface corresponds to a method
in this class. E.g. to marshal the `create_pool` request on an
`wl_shm` interface, the `create_pool()` method of an instance of
`shm_t` has to be called:
shm_t shm;
int fd;
int32_t size;
// ... insert the initialisation of the above here ...
shm_pool_t shm_pool = shm.create_pool(fd, size);
Some methods return newly created instances of other classes. In this
example an instance of the class `shm_pool_t` is returned.
Events are implemented using function objects. To react to an event, a
function object with the correct signature has to be assigned to
it. These can not only be static functions, but also member functions
or closures. E.g. to react to global events from the registry using a
lambda expression, one could write:
registry.on_global() = [] (uint32_t name, std::string interface,
uint32_t version)
{ std::cout << interface << " v" << version << std::endl; };
An example for using member functions can be found in
example/opengles.cpp or example/shm.cpp.
The Wayland protocol uses arrays in some of its events and requests.
Since these arrays can have arbitrary content, they are not directly
mapped to a std::vector. Instead there is a new type array_t, which
can converted to and from a std::vectory with an user specified type.
For example:
keyboard.on_enter() = [] (uint32_t serial, surface_t surface,
array_t keys)
{ std::vector<uint32_t> vec = keys; };
## Servers
Instead of proxies the object wrappers of a specific interface are
called resources and are represented by a `resource_t` object. They
are pretty similar to proxies, as they have events and requests.
The server bindings allow the creation of global objects. These can
be constructed by prepending `global_` to the class name. They have
to be initialised with the display object:
display_t display;
global_output_t output(display);
Global objects only have a single event called "on_bind", that is
called whenever a client binds to this interface. The event then
supplies the corresponding resource:
output.on_bind() = [this] (client_t client, output_t output) { /* ... */ }
A `client_t` object which represents the client connected to the
server is also supplied with the bind event.
The client and resource objects should be saved for later to be able
to identify the exact origin of a request. To help with that, all
server-side wrapper classes allow saving of user data through the
`user_data()` member which returns a reference to an `any` type.
## Compiling
To compile code that using this library, pkg-config can be used to
take care of the compiler flags. Assuming the source file is called
`foo.cpp` and the executable shall be called `foo` type:
$ c++ -c foo.cpp `pkg-config --cflags wayland-client++` -o foo.o
$ c++ foo.o `pkg-config --libs wayland-client++` -o foo
If the library and headers are installed in the default search paths
of the compiler, the linker flag `-lwayland-client++` can also
directly be specified on the command line.
If the Wayland cursor classes and/or EGL is used, the corresponding
libreries `wayland-cursor++` and/or `wayland-egl++` need to be linked
in as well. If any extension protocols such as xdg-shell are used,
the library `wayland-client-extra++` should be linked in as well,
and if the Waylans server bindings are used, the library
`wayland-server++` needs to be linked in as well.
Further examples can be found in the examples/Makefile.
|