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