Wayland++ 0.2.9
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
37#include <wayland-client-core.h>
38
39#define wl_array_for_each_cpp(pos, array) \
40 for((pos) = static_cast<decltype(pos)>((array)->data); \
41 reinterpret_cast<const char*>(pos) < (reinterpret_cast<const char*>((array)->data) + (array)->size); \
42 (pos)++)
43
44namespace wayland
45{
46 class proxy_t;
47
48 class array_t;
49
50 namespace detail
51 {
60 int check_return_value(int return_value, std::string const &function_name);
61
67 template<typename native_t>
69 {
70 private:
71 native_t *object = nullptr;
72
73 protected:
74 basic_wrapper(native_t *object)
75 : object{object}
76 {
77 }
78
79 public:
80 basic_wrapper() = default;
81 ~basic_wrapper() noexcept = default;
82
83 basic_wrapper(basic_wrapper const &other)
84 {
85 *this = other;
86 }
87
88 basic_wrapper(basic_wrapper &&other) noexcept
89 {
90 *this = std::move(other);
91 }
92
93 native_t *c_ptr() const
94 {
95 if(!object)
96 throw std::runtime_error("Tried to access empty object");
97 return object;
98 }
99
100 bool has_object() const
101 {
102 return object;
103 }
104
105 operator bool() const
106 {
107 return has_object();
108 }
109
110 operator native_t*() const
111 {
112 return c_ptr();
113 }
114
115 basic_wrapper& operator=(const basic_wrapper &right)
116 {
117 // Check for self-assignment
118 if(this == &right)
119 return *this;
120 object = right.object;
121 return *this;
122 }
123
124 basic_wrapper& operator=(basic_wrapper &&right) noexcept
125 {
126 std::swap(object, right.object);
127 return *this;
128 }
129
130 bool operator==(const basic_wrapper &right) const
131 {
132 return object == right.object;
133 }
134
135 bool operator!=(const basic_wrapper &right) const
136 {
137 return !(*this == right); // Reuse equals operator
138 }
139 };
140
146 template<typename native_t>
148 {
149 private:
150 std::shared_ptr<native_t> object;
151
152 protected:
153 refcounted_wrapper(std::shared_ptr<native_t> object)
154 : object{std::move(object)}
155 {
156 }
157
158 std::shared_ptr<native_t> ref_ptr() const
159 {
160 return object;
161 }
162
163 public:
164 refcounted_wrapper() = default;
165 ~refcounted_wrapper() noexcept = default;
166
168 {
169 *this = other;
170 }
171
172 refcounted_wrapper(refcounted_wrapper &&other) noexcept
173 {
174 *this = std::move(other);
175 }
176
177 native_t *c_ptr() const
178 {
179 if(!object)
180 throw std::runtime_error("Tried to access empty object");
181 return object.get();
182 }
183
184 bool has_object() const
185 {
186 return !!object;
187 }
188
189 operator bool() const
190 {
191 return has_object();
192 }
193
194 operator native_t*() const
195 {
196 return c_ptr();
197 }
198
199 refcounted_wrapper& operator=(const refcounted_wrapper &right)
200 {
201 // Check for self-assignment
202 if(this == &right)
203 return *this;
204 object = right.object;
205 return *this;
206 }
207
208 refcounted_wrapper& operator=(refcounted_wrapper &&right) noexcept
209 {
210 std::swap(object, right.object);
211 return *this;
212 }
213
214 bool operator==(const refcounted_wrapper &right) const
215 {
216 return object == right.object;
217 }
218
219 bool operator!=(const refcounted_wrapper &right) const
220 {
221 return !(*this == right); // Reuse equals operator
222 }
223 };
224
225 class any
226 {
227 private:
228 class base
229 {
230 public:
231 base() = default;
232 base(const base&) = default;
233 base(base&&) noexcept = default;
234 base& operator=(const base&) = default;
235 base& operator=(base&&) noexcept = default;
236 virtual ~base() noexcept = default;
237 virtual const std::type_info &type_info() const = 0;
238 virtual base *clone() const = 0;
239 };
240
241 template <typename T>
242 class derived : public base
243 {
244 private:
245 T val;
246 friend class any;
247
248 public:
249 derived(T t)
250 : val(std::move(t)) { }
251
252 const std::type_info &type_info() const override
253 {
254 return typeid(T);
255 }
256
257 base *clone() const override
258 {
259 return new derived<T>(val);
260 }
261 };
262
263 base *val = nullptr;
264
265 public:
266 any() = default;
267
268 any(const any &a)
269 : val(a.val ? a.val->clone() : nullptr) { }
270
271 any(any &&a) noexcept
272 {
273 operator=(std::move(a));
274 }
275
276 template <typename T>
277 any(const T &t)
278 : val(new derived<T>(t)) { }
279
280 ~any() noexcept
281 {
282 delete val;
283 }
284
285 any &operator=(const any &a)
286 {
287 if(&a != this)
288 {
289 delete val;
290 val = a.val ? a.val->clone() : nullptr;
291 }
292 return *this;
293 }
294
295 any &operator=(any &&a) noexcept
296 {
297 std::swap(val, a.val);
298 return *this;
299 }
300
301 template <typename T>
302 any &operator=(const T &t)
303 {
304 if(val && typeid(T) == val->type_info())
305 static_cast<derived<T>*>(val)->val = t;
306 else
307 {
308 delete val;
309 val = new derived<T>(t);
310 }
311 return *this;
312 }
313
314 template <typename T>
315 T &get()
316 {
317 if(val && typeid(T) == val->type_info())
318 return static_cast<derived<T>*>(val)->val;
319 throw std::bad_cast();
320 }
321
322 template <typename T>
323 const T &get() const
324 {
325 if(val && typeid(T) == val->type_info())
326 return static_cast<derived<T>*>(val)->val;
327 throw std::bad_cast();
328 }
329 };
330
331 template<unsigned int size, int id = 0>
332 class bitfield
333 {
334 uint32_t v = 0;
335 static const uint32_t mask = (1 << size) - 1;
336
337 public:
338 explicit bitfield(const uint32_t value = 0)
339 : v(value)
340 {
341 }
342
343 explicit operator uint32_t() const
344 {
345 return v;
346 }
347
348 operator bool() const
349 {
350 return v;
351 }
352
353 bitfield(const bitfield<size, id> &b)
354 {
355 operator=(b);
356 }
357
358 bitfield(bitfield<size, id>&&) noexcept = default;
359
360 ~bitfield() noexcept = default;
361
362 bool operator==(const bitfield<size, id> &b)
363 {
364 return v == b.v;
365 }
366
367 bool operator!=(const bitfield<size, id> &b)
368 {
369 return !operator==(b);
370 }
371
372 bitfield<size, id> &operator=(const bitfield<size, id> &b)
373 {
374 // Check for self-assignment
375 if(this != &b)
376 v = static_cast<uint32_t>(b);
377 return *this;
378 }
379
380 bitfield<size, id> &operator=(bitfield<size, id> &&) noexcept = default;
381
382 bitfield<size, id> operator|(const bitfield<size, id> &b) const
383 {
384 return bitfield<size, id>(v | static_cast<uint32_t>(b));
385 }
386
387 bitfield<size, id> operator&(const bitfield<size, id> &b) const
388 {
389 return bitfield<size, id>(v & static_cast<uint32_t>(b));
390 }
391
392 bitfield<size, id> operator^(const bitfield<size, id> &b) const
393 {
394 return bitfield<size, id>((v ^ static_cast<uint32_t>(b)) & mask);
395 }
396
397 bitfield<size, id> operator~() const
398 {
399 return bitfield<size, id>(~v & mask);
400 }
401
402 bitfield<size, id> &operator|=(const bitfield<size, id> &b)
403 {
404 operator=(*this | b);
405 return *this;
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
421 class argument_t
422 {
423 private:
424 wl_argument argument = { .i = 0 };
425 bool is_array{false};
426
427 // Uninitialized argument - only for internal use
428 argument_t() = default;
429 public:
430
431 argument_t(const argument_t &arg);
432 argument_t(argument_t &&) noexcept = default;
433 argument_t &operator=(const argument_t &arg);
434 argument_t &operator=(argument_t&&) noexcept = default;
435 ~argument_t() noexcept;
436
437 // handles integers
438 argument_t(uint32_t i);
439 argument_t(int32_t i);
440
441 // handles wl_fixed_t
442 argument_t(double f);
443
444 // handles strings
445 argument_t(const std::string &s);
446
447 // handles objects
448 argument_t(wl_object *o);
449
450 // handles arrays
451 argument_t(const array_t& a);
452
453 // handles null objects, for example for new-id arguments
454 argument_t(std::nullptr_t);
455
456 // handles file descriptors (have same type as signed integers, so extra function)
457 static argument_t fd(int fileno);
458
462 wl_argument get_c_argument() const;
463 };
464 }
465
466 class array_t
467 {
468 private:
469 wl_array a = { 0, 0, nullptr };
470
471 array_t(wl_array *arr);
472 void get(wl_array *arr) const;
473
474 friend class proxy_t;
475 friend class detail::argument_t;
476
477 public:
478 array_t();
479 array_t(const array_t &arr);
480 array_t(array_t &&arr) noexcept;
481
482 template <typename T> array_t(const std::vector<T> &v)
483 {
484 wl_array_init(&a);
485 wl_array_add(&a, v.size()*sizeof(T));
486 T *p = nullptr;
487 unsigned int c = 0;
488 wl_array_for_each_cpp(p, &a)
489 *p = v.at(c++);
490 }
491
492 ~array_t();
493 array_t &operator=(const array_t &arr);
494 array_t &operator=(array_t &&arr) noexcept;
495
496 template <typename T> array_t &operator=(const std::vector<T> &v)
497 {
498 wl_array_release(&a);
499 wl_array_init(&a);
500 wl_array_add(&a, v.size()*sizeof(T));
501 T *p = nullptr;
502 unsigned int c = 0;
503 wl_array_for_each_cpp(p, &a)
504 *p = v.at(c++);
505 return *this;
506 }
507
508 template <typename T> operator std::vector<T>() const
509 {
510 std::vector<T> v;
511 T *p = nullptr;
512 wl_array_for_each_cpp(p, &a)
513 v.push_back(*p);
514 return v;
515 }
516 };
517}
518
519#endif
Non-refcounted wrapper for C objects.
Refcounted wrapper for C objects.