Loading...
Searching...
No Matches
wayland-util.hpp
/*
* Copyright (c) 2014-2022, Nils Christopher Brause, Philipp Kerling
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef WAYLAND_UTIL_HPP
#define WAYLAND_UTIL_HPP
#include <algorithm>
#include <memory>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <utility>
#include <vector>
#include <cstdint>
#include <wayland-client-core.h>
#define wl_array_for_each_cpp(pos, array) \
for((pos) = static_cast<decltype(pos)>((array)->data); \
reinterpret_cast<const char*>(pos) < (reinterpret_cast<const char*>((array)->data) + (array)->size); \
(pos)++)
namespace wayland
{
class proxy_t;
class array_t;
namespace server
{
class resource_t;
}
namespace detail
{
int check_return_value(int return_value, std::string const &function_name);
template<typename native_t>
class basic_wrapper
{
private:
native_t *object = nullptr;
protected:
basic_wrapper(native_t *object)
: object{object}
{
}
public:
basic_wrapper() = default;
~basic_wrapper() noexcept = default;
basic_wrapper(basic_wrapper const &other)
{
*this = other;
}
basic_wrapper(basic_wrapper &&other) noexcept
{
*this = std::move(other);
}
native_t *c_ptr() const
{
if(!object)
throw std::runtime_error("Tried to access empty object");
return object;
}
bool has_object() const
{
return object;
}
operator bool() const
{
return has_object();
}
operator native_t*() const
{
return c_ptr();
}
basic_wrapper& operator=(const basic_wrapper &right)
{
// Check for self-assignment
if(this == &right)
return *this;
object = right.object;
return *this;
}
basic_wrapper& operator=(basic_wrapper &&right) noexcept
{
std::swap(object, right.object);
return *this;
}
bool operator==(const basic_wrapper &right) const
{
return object == right.object;
}
bool operator!=(const basic_wrapper &right) const
{
return !(*this == right); // Reuse equals operator
}
};
template<typename native_t>
class refcounted_wrapper
{
private:
std::shared_ptr<native_t> object;
protected:
refcounted_wrapper(std::shared_ptr<native_t> object)
: object{std::move(object)}
{
}
std::shared_ptr<native_t> ref_ptr() const
{
return object;
}
public:
refcounted_wrapper() = default;
~refcounted_wrapper() noexcept = default;
refcounted_wrapper(refcounted_wrapper const &other)
{
*this = other;
}
refcounted_wrapper(refcounted_wrapper &&other) noexcept
{
*this = std::move(other);
}
native_t *c_ptr() const
{
if(!object)
throw std::runtime_error("Tried to access empty object");
return object.get();
}
bool has_object() const
{
return !!object;
}
operator bool() const
{
return has_object();
}
operator native_t*() const
{
return c_ptr();
}
refcounted_wrapper& operator=(const refcounted_wrapper &right)
{
// Check for self-assignment
if(this == &right)
return *this;
object = right.object;
return *this;
}
refcounted_wrapper& operator=(refcounted_wrapper &&right) noexcept
{
std::swap(object, right.object);
return *this;
}
bool operator==(const refcounted_wrapper &right) const
{
return object == right.object;
}
bool operator!=(const refcounted_wrapper &right) const
{
return !(*this == right); // Reuse equals operator
}
};
class any
{
private:
class base
{
public:
base() = default;
base(const base&) = default;
base(base&&) noexcept = default;
base& operator=(const base&) = default;
base& operator=(base&&) noexcept = default;
virtual ~base() noexcept = default;
virtual const std::type_info &type_info() const = 0;
virtual base *clone() const = 0;
};
template <typename T>
class derived : public base
{
private:
T val;
friend class any;
public:
derived(T t)
: val(std::move(t)) { }
const std::type_info &type_info() const override
{
return typeid(T);
}
base *clone() const override
{
return new derived<T>(val);
}
};
base *val = nullptr;
public:
any() = default;
any(const any &a)
: val(a.val ? a.val->clone() : nullptr) { }
any(any &&a) noexcept
{
operator=(std::move(a));
}
template <typename T>
any(const T &t)
: val(new derived<T>(t)) { }
~any() noexcept
{
delete val;
}
any &operator=(const any &a)
{
if(&a != this)
{
delete val;
val = a.val ? a.val->clone() : nullptr;
}
return *this;
}
any &operator=(any &&a) noexcept
{
std::swap(val, a.val);
return *this;
}
template <typename T>
any &operator=(const T &t)
{
if(val && typeid(T) == val->type_info())
static_cast<derived<T>*>(val)->val = t;
else
{
delete val;
val = new derived<T>(t);
}
return *this;
}
template <typename T>
T &get()
{
if(val && typeid(T) == val->type_info())
return static_cast<derived<T>*>(val)->val;
throw std::bad_cast();
}
template <typename T>
const T &get() const
{
if(val && typeid(T) == val->type_info())
return static_cast<derived<T>*>(val)->val;
throw std::bad_cast();
}
};
template<unsigned int size, int id = 0>
class bitfield
{
uint32_t v = 0;
static const uint32_t mask = (1 << size) - 1;
public:
explicit bitfield(const uint32_t value = 0)
: v(value)
{
}
explicit operator uint32_t() const
{
return v;
}
operator bool() const
{
return v;
}
bitfield(const bitfield<size, id> &b)
{
operator=(b);
}
bitfield(bitfield<size, id>&&) noexcept = default;
~bitfield() noexcept = default;
bool operator==(const bitfield<size, id> &b)
{
return v == b.v;
}
bool operator!=(const bitfield<size, id> &b)
{
return !operator==(b);
}
bitfield<size, id> &operator=(const bitfield<size, id> &b)
{
// Check for self-assignment
if(this != &b)
v = static_cast<uint32_t>(b);
return *this;
}
bitfield<size, id> &operator=(bitfield<size, id> &&) noexcept = default;
bitfield<size, id> operator|(const bitfield<size, id> &b) const
{
return bitfield<size, id>(v | static_cast<uint32_t>(b));
}
bitfield<size, id> operator&(const bitfield<size, id> &b) const
{
return bitfield<size, id>(v & static_cast<uint32_t>(b));
}
bitfield<size, id> operator^(const bitfield<size, id> &b) const
{
return bitfield<size, id>((v ^ static_cast<uint32_t>(b)) & mask);
}
bitfield<size, id> operator~() const
{
return bitfield<size, id>(~v & mask);
}
bitfield<size, id> &operator|=(const bitfield<size, id> &b)
{
operator=(*this | b);
return *this;
}
bitfield<size, id> &operator&=(const bitfield<size, id> &b)
{
operator=(*this & b);
return *this;
}
bitfield<size, id> &operator^=(const bitfield<size, id> &b)
{
operator=(*this ^ b);
return *this;
}
};
class argument_t
{
private:
wl_argument argument = { .i = 0 };
bool is_array{false};
// Uninitialized argument - only for internal use
argument_t() = default;
public:
argument_t(const argument_t &arg);
argument_t(argument_t &&) noexcept = default;
argument_t &operator=(const argument_t &arg);
argument_t &operator=(argument_t&&) noexcept = default;
~argument_t() noexcept;
// handles integers
argument_t(uint32_t i);
argument_t(int32_t i);
// handles wl_fixed_t
argument_t(double f);
// handles strings
argument_t(const std::string &s);
// handles objects
argument_t(wl_object *o);
// handles arrays
argument_t(const array_t& a);
// handles null objects, for example for new-id arguments
argument_t(std::nullptr_t);
// handles file descriptors (have same type as signed integers, so extra function)
static argument_t fd(int fileno);
wl_argument get_c_argument() const;
};
}
class array_t
{
private:
wl_array a = { 0, 0, nullptr };
array_t(wl_array *arr);
void get(wl_array *arr) const;
friend class proxy_t;
friend class detail::argument_t;
friend class server::resource_t;
public:
array_t();
array_t(const array_t &arr);
array_t(array_t &&arr) noexcept;
template <typename T> array_t(const std::vector<T> &v)
{
wl_array_init(&a);
wl_array_add(&a, v.size()*sizeof(T));
T *p = nullptr;
unsigned int c = 0;
wl_array_for_each_cpp(p, &a)
*p = v.at(c++);
}
~array_t();
array_t &operator=(const array_t &arr);
array_t &operator=(array_t &&arr) noexcept;
template <typename T> array_t &operator=(const std::vector<T> &v)
{
wl_array_release(&a);
wl_array_init(&a);
wl_array_add(&a, v.size()*sizeof(T));
T *p = nullptr;
unsigned int c = 0;
wl_array_for_each_cpp(p, &a)
*p = v.at(c++);
return *this;
}
template <typename T> operator std::vector<T>() const
{
std::vector<T> v;
T *p = nullptr;
wl_array_for_each_cpp(p, &a)
v.push_back(*p);
return v;
}
};
}
#endif
wayland::detail::basic_wrapper
Non-refcounted wrapper for C objects.
Definition wayland-util.hpp:75
wayland::detail::refcounted_wrapper
Refcounted wrapper for C objects.
Definition wayland-util.hpp:154