Wayland++ 1.0.0
C++ Bindings for Wayland
wayland-util.hpp
1/*
2 * Copyright (c) 2014-2022, Nils Christopher Brause, Philipp Kerling
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef WAYLAND_UTIL_HPP
27#define WAYLAND_UTIL_HPP
28
29#include <algorithm>
30#include <memory>
31#include <stdexcept>
32#include <string>
33#include <typeinfo>
34#include <utility>
35#include <vector>
36#include <cstdint>
37
38#include <wayland-client-core.h>
39
40#define wl_array_for_each_cpp(pos, array) \
41 for((pos) = static_cast<decltype(pos)>((array)->data); \
42 reinterpret_cast<const char*>(pos) < (reinterpret_cast<const char*>((array)->data) + (array)->size); \
43 (pos)++)
44
45namespace wayland
46{
47 class proxy_t;
48
49 class array_t;
50
51 namespace server
52 {
53 class resource_t;
54 }
55
56 namespace detail
57 {
66 int check_return_value(int return_value, std::string const &function_name);
67
73 template<typename native_t>
75 {
76 private:
77 native_t *object = nullptr;
78
79 protected:
80 basic_wrapper(native_t *object)
81 : object{object}
82 {
83 }
84
85 public:
86 basic_wrapper() = default;
87 ~basic_wrapper() noexcept = default;
88
89 basic_wrapper(basic_wrapper const &other)
90 {
91 *this = other;
92 }
93
94 basic_wrapper(basic_wrapper &&other) noexcept
95 {
96 *this = std::move(other);
97 }
98
99 native_t *c_ptr() const
100 {
101 if(!object)
102 throw std::runtime_error("Tried to access empty object");
103 return object;
104 }
105
106 bool has_object() const
107 {
108 return object;
109 }
110
111 operator bool() const
112 {
113 return has_object();
114 }
115
116 operator native_t*() const
117 {
118 return c_ptr();
119 }
120
121 basic_wrapper& operator=(const basic_wrapper &right)
122 {
123 // Check for self-assignment
124 if(this == &right)
125 return *this;
126 object = right.object;
127 return *this;
128 }
129
130 basic_wrapper& operator=(basic_wrapper &&right) noexcept
131 {
132 std::swap(object, right.object);
133 return *this;
134 }
135
136 bool operator==(const basic_wrapper &right) const
137 {
138 return object == right.object;
139 }
140
141 bool operator!=(const basic_wrapper &right) const
142 {
143 return !(*this == right); // Reuse equals operator
144 }
145 };
146
152 template<typename native_t>
154 {
155 private:
156 std::shared_ptr<native_t> object;
157
158 protected:
159 refcounted_wrapper(std::shared_ptr<native_t> object)
160 : object{std::move(object)}
161 {
162 }
163
164 std::shared_ptr<native_t> ref_ptr() const
165 {
166 return object;
167 }
168
169 public:
170 refcounted_wrapper() = default;
171 ~refcounted_wrapper() noexcept = default;
172
174 {
175 *this = other;
176 }
177
178 refcounted_wrapper(refcounted_wrapper &&other) noexcept
179 {
180 *this = std::move(other);
181 }
182
183 native_t *c_ptr() const
184 {
185 if(!object)
186 throw std::runtime_error("Tried to access empty object");
187 return object.get();
188 }
189
190 bool has_object() const
191 {
192 return !!object;
193 }
194
195 operator bool() const
196 {
197 return has_object();
198 }
199
200 operator native_t*() const
201 {
202 return c_ptr();
203 }
204
205 refcounted_wrapper& operator=(const refcounted_wrapper &right)
206 {
207 // Check for self-assignment
208 if(this == &right)
209 return *this;
210 object = right.object;
211 return *this;
212 }
213
214 refcounted_wrapper& operator=(refcounted_wrapper &&right) noexcept
215 {
216 std::swap(object, right.object);
217 return *this;
218 }
219
220 bool operator==(const refcounted_wrapper &right) const
221 {
222 return object == right.object;
223 }
224
225 bool operator!=(const refcounted_wrapper &right) const
226 {
227 return !(*this == right); // Reuse equals operator
228 }
229 };
230
231 class any
232 {
233 private:
234 class base
235 {
236 public:
237 base() = default;
238 base(const base&) = default;
239 base(base&&) noexcept = default;
240 base& operator=(const base&) = default;
241 base& operator=(base&&) noexcept = default;
242 virtual ~base() noexcept = default;
243 virtual const std::type_info &type_info() const = 0;
244 virtual base *clone() const = 0;
245 };
246
247 template <typename T>
248 class derived : public base
249 {
250 private:
251 T val;
252 friend class any;
253
254 public:
255 derived(T t)
256 : val(std::move(t)) { }
257
258 const std::type_info &type_info() const override
259 {
260 return typeid(T);
261 }
262
263 base *clone() const override
264 {
265 return new derived<T>(val);
266 }
267 };
268
269 base *val = nullptr;
270
271 public:
272 any() = default;
273
274 any(const any &a)
275 : val(a.val ? a.val->clone() : nullptr) { }
276
277 any(any &&a) noexcept
278 {
279 operator=(std::move(a));
280 }
281
282 template <typename T>
283 any(const T &t)
284 : val(new derived<T>(t)) { }
285
286 ~any() noexcept
287 {
288 delete val;
289 }
290
291 any &operator=(const any &a)
292 {
293 if(&a != this)
294 {
295 delete val;
296 val = a.val ? a.val->clone() : nullptr;
297 }
298 return *this;
299 }
300
301 any &operator=(any &&a) noexcept
302 {
303 std::swap(val, a.val);
304 return *this;
305 }
306
307 template <typename T>
308 any &operator=(const T &t)
309 {
310 if(val && typeid(T) == val->type_info())
311 static_cast<derived<T>*>(val)->val = t;
312 else
313 {
314 delete val;
315 val = new derived<T>(t);
316 }
317 return *this;
318 }
319
320 template <typename T>
321 T &get()
322 {
323 if(val && typeid(T) == val->type_info())
324 return static_cast<derived<T>*>(val)->val;
325 throw std::bad_cast();
326 }
327
328 template <typename T>
329 const T &get() const
330 {
331 if(val && typeid(T) == val->type_info())
332 return static_cast<derived<T>*>(val)->val;
333 throw std::bad_cast();
334 }
335 };
336
337 template<unsigned int size, int id = 0>
338 class bitfield
339 {
340 uint32_t v = 0;
341 static const uint32_t mask = (1 << size) - 1;
342
343 public:
344 explicit bitfield(const uint32_t value = 0)
345 : v(value)
346 {
347 }
348
349 explicit operator uint32_t() const
350 {
351 return v;
352 }
353
354 operator bool() const
355 {
356 return v;
357 }
358
359 bitfield(const bitfield<size, id> &b)
360 {
361 operator=(b);
362 }
363
364 bitfield(bitfield<size, id>&&) noexcept = default;
365
366 ~bitfield() noexcept = default;
367
368 bool operator==(const bitfield<size, id> &b)
369 {
370 return v == b.v;
371 }
372
373 bool operator!=(const bitfield<size, id> &b)
374 {
375 return !operator==(b);
376 }
377
378 bitfield<size, id> &operator=(const bitfield<size, id> &b)
379 {
380 // Check for self-assignment
381 if(this != &b)
382 v = static_cast<uint32_t>(b);
383 return *this;
384 }
385
386 bitfield<size, id> &operator=(bitfield<size, id> &&) noexcept = default;
387
388 bitfield<size, id> operator|(const bitfield<size, id> &b) const
389 {
390 return bitfield<size, id>(v | static_cast<uint32_t>(b));
391 }
392
393 bitfield<size, id> operator&(const bitfield<size, id> &b) const
394 {
395 return bitfield<size, id>(v & static_cast<uint32_t>(b));
396 }
397
398 bitfield<size, id> operator^(const bitfield<size, id> &b) const
399 {
400 return bitfield<size, id>((v ^ static_cast<uint32_t>(b)) & mask);
401 }
402
403 bitfield<size, id> operator~() const
404 {
405 return bitfield<size, id>(~v & mask);
406 }
407
408 bitfield<size, id> &operator|=(const bitfield<size, id> &b)
409 {
410 operator=(*this | b);
411 return *this;
412 }
413
414 bitfield<size, id> &operator&=(const bitfield<size, id> &b)
415 {
416 operator=(*this & b);
417 return *this;
418 }
419
420 bitfield<size, id> &operator^=(const bitfield<size, id> &b)
421 {
422 operator=(*this ^ b);
423 return *this;
424 }
425 };
426
427 class argument_t
428 {
429 private:
430 wl_argument argument = { .i = 0 };
431 bool is_array{false};
432
433 // Uninitialized argument - only for internal use
434 argument_t() = default;
435 public:
436
437 argument_t(const argument_t &arg);
438 argument_t(argument_t &&) noexcept = default;
439 argument_t &operator=(const argument_t &arg);
440 argument_t &operator=(argument_t&&) noexcept = default;
441 ~argument_t() noexcept;
442
443 // handles integers
444 argument_t(uint32_t i);
445 argument_t(int32_t i);
446
447 // handles wl_fixed_t
448 argument_t(double f);
449
450 // handles strings
451 argument_t(const std::string &s);
452
453 // handles objects
454 argument_t(wl_object *o);
455
456 // handles arrays
457 argument_t(const array_t& a);
458
459 // handles null objects, for example for new-id arguments
460 argument_t(std::nullptr_t);
461
462 // handles file descriptors (have same type as signed integers, so extra function)
463 static argument_t fd(int fileno);
464
468 wl_argument get_c_argument() const;
469 };
470 }
471
472 class array_t
473 {
474 private:
475 wl_array a = { 0, 0, nullptr };
476
477 array_t(wl_array *arr);
478 void get(wl_array *arr) const;
479
480 friend class proxy_t;
481 friend class detail::argument_t;
482 friend class server::resource_t;
483
484 public:
485 array_t();
486 array_t(const array_t &arr);
487 array_t(array_t &&arr) noexcept;
488
489 template <typename T> array_t(const std::vector<T> &v)
490 {
491 wl_array_init(&a);
492 wl_array_add(&a, v.size()*sizeof(T));
493 T *p = nullptr;
494 unsigned int c = 0;
495 wl_array_for_each_cpp(p, &a)
496 *p = v.at(c++);
497 }
498
499 ~array_t();
500 array_t &operator=(const array_t &arr);
501 array_t &operator=(array_t &&arr) noexcept;
502
503 template <typename T> array_t &operator=(const std::vector<T> &v)
504 {
505 wl_array_release(&a);
506 wl_array_init(&a);
507 wl_array_add(&a, v.size()*sizeof(T));
508 T *p = nullptr;
509 unsigned int c = 0;
510 wl_array_for_each_cpp(p, &a)
511 *p = v.at(c++);
512 return *this;
513 }
514
515 template <typename T> operator std::vector<T>() const
516 {
517 std::vector<T> v;
518 T *p = nullptr;
519 wl_array_for_each_cpp(p, &a)
520 v.push_back(*p);
521 return v;
522 }
523 };
524}
525
526#endif
Non-refcounted wrapper for C objects.
Refcounted wrapper for C objects.