Loading...
Searching...
No Matches
wayland-server.hpp
Go to the documentation of this file.
/*
* Copyright (c) 2022, Nils Christopher Brause
* 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_SERVER_HPP
#define WAYLAND_SERVER_HPP
#include <atomic>
#include <functional>
#include <list>
#include <memory>
#include <string>
#include <cstdint>
#include <wayland-server-core.h>
#include <wayland-util.hpp>
namespace wayland
{
namespace server
{
namespace detail
{
struct listener_t
{
wl_listener listener = { { nullptr, nullptr }, nullptr };
void *user = nullptr;
};
}
using log_handler = std::function<void(std::string)>;
void set_log_handler(const log_handler& handler);
class client_t;
class global_base_t;
template <class resource> class global_t;
class event_loop_t;
class event_source_t;
class display_t
{
private:
struct data_t
{
std::function<void()> destroy;
std::function<void(client_t&)> client_created;
detail::listener_t destroy_listener;
detail::listener_t client_created_listener;
std::function<bool(client_t, global_base_t)> filter_func;
wayland::detail::any user_data;
std::atomic<unsigned int> counter{1};
};
wl_display *display = nullptr;
data_t *data = nullptr;
static void destroy_func(wl_listener *listener, void *data);
static void client_created_func(wl_listener *listener, void *cl);
static data_t *wl_display_get_user_data(wl_display *display);
static bool c_filter_func(const wl_client *client, const wl_global *global, void *data);
protected:
display_t(wl_display *c);
void init();
void fini();
friend class client_t;
public:
display_t();
~display_t();
display_t(const display_t& d);
display_t(display_t&& d) noexcept;
display_t &operator=(const display_t& d);
display_t &operator=(display_t&& d) noexcept;
bool operator==(const display_t& d) const;
wl_display *c_ptr() const;
wayland::detail::any &user_data();
event_loop_t get_event_loop() const;
int add_socket(const std::string& name) const;
std::string add_socket_auto() const;
int add_socket_fd(int sock_fd) const;
void terminate() const;
void run() const;
void flush_clients() const;
uint32_t get_serial() const;
uint32_t next_serial() const;
std::function<void()> &on_destroy();
std::function<void(client_t&)> &on_client_created();
client_t client_create(int fd);
std::list<client_t> get_client_list() const;
void set_global_filter(const std::function<bool(client_t, global_base_t)>& filter);
};
class resource_t;
class client_t
{
private:
struct data_t
{
wl_client *client = nullptr;
std::function<void()> destroy;
detail::listener_t destroy_listener;
wayland::detail::any user_data;
std::atomic<unsigned int> counter{1};
bool destroyed = false;
};
wl_client *client = nullptr;
data_t *data = nullptr;
static void destroy_func(wl_listener *listener, void *data);
static wl_iterator_result resource_iterator(wl_resource *resource, void *data);
static data_t *wl_client_get_user_data(wl_client *client);
protected:
client_t(wl_client *c);
void init();
void fini();
friend class display_t;
friend class resource_t;
template <class resource> friend class global_t;
public:
client_t(display_t &display, int fd);
client_t() = delete;
~client_t();
client_t(const client_t &c);
client_t(client_t &&c) noexcept;
client_t &operator=(const client_t& c);
client_t &operator=(client_t&& c) noexcept;
bool operator==(const client_t &c) const;
wl_client *c_ptr() const;
wayland::detail::any &user_data();
void flush() const;
void get_credentials(pid_t &pid, uid_t &uid, gid_t &gid) const;
int get_fd() const;
std::function<void()> &on_destroy();
resource_t get_object(uint32_t id);
void post_no_memory() const;
void post_implementation_error(std::string const& msg) const;
template <typename...types>
void post_implementation_error(std::string const& msg, types&&... args)
{
wl_client_post_implementation_error(c_ptr(), msg.c_str(), std::forward<types...>(args...));
}
display_t get_display() const;
std::list<resource_t> get_resource_list() const;
};
class resource_t
{
protected:
// base class for event listener storage.
struct events_base_t
{
events_base_t() = default;
events_base_t(const events_base_t& e) = default;
events_base_t(events_base_t&& e) = default;
events_base_t& operator=(const events_base_t& e) = default;
events_base_t& operator=(events_base_t&& e) = default;
virtual ~events_base_t() = default;
};
private:
struct data_t
{
std::shared_ptr<events_base_t> events;
std::function<void()> destroy;
detail::listener_t destroy_listener;
wayland::detail::any user_data;
std::atomic<unsigned int> counter{1};
bool destroyed = false;
};
wl_resource *resource = nullptr;
data_t *data = nullptr;
static void destroy_func(wl_listener *listener, void *data);
static int c_dispatcher(const void *implementation, void *target,
uint32_t opcode, const wl_message *message,
wl_argument *args);
static int dummy_dispatcher(int opcode, const std::vector<wayland::detail::any>& args, const std::shared_ptr<resource_t::events_base_t>& events);
protected:
// Interface desctiption filled in by the each interface class
static constexpr const wl_interface *interface = nullptr;
/*
Sets the dispatcher and its user data. User data must be an
instance of a class derived from events_base_t, allocated with
new. Will automatically be deleted upon destruction.
*/
void set_events(const std::shared_ptr<events_base_t>& events,
int(*dispatcher)(int, const std::vector<wayland::detail::any>&, const std::shared_ptr<resource_t::events_base_t>&));
// Retrieve the perviously set user data
std::shared_ptr<events_base_t> get_events() const;
void post_event_array(uint32_t opcode, const std::vector<wayland::detail::argument_t>& v) const;
void queue_event_array(uint32_t opcode, const std::vector<wayland::detail::argument_t>& v) const;
template <typename...T>
void post_event(uint32_t opcode, T...args) const
{
std::vector<wayland::detail::argument_t> v = { wayland::detail::argument_t(args)... };
if(c_ptr())
post_event_array(opcode, v);
}
template <typename...T>
void queue_event(uint32_t opcode, T...args) const
{
std::vector<wayland::detail::argument_t> v = { wayland::detail::argument_t(args)... };
if(c_ptr())
queue_event_array(opcode, v);
}
template <typename...T>
void send_event(bool post, uint32_t opcode, T...args) const
{
if(post)
post_event(opcode, args...);
else
queue_event(opcode, args...);
}
void post_error(uint32_t code, const std::string& msg) const;
resource_t(wl_resource *c);
void init();
void fini();
friend class client_t;
public:
resource_t() = default;
resource_t(const client_t& client, const wl_interface *interface, int version, uint32_t id);
~resource_t();
resource_t(const resource_t &r);
resource_t(resource_t &&r) noexcept;
resource_t &operator=(const resource_t& r);
resource_t &operator=(resource_t&& r) noexcept;
bool operator==(const resource_t& r) const;
operator bool() const;
wl_resource *c_ptr() const;
wayland::detail::any &user_data();
bool proxy_has_object() const;
void post_no_memory() const;
uint32_t get_id() const;
client_t get_client() const;
unsigned int get_version() const;
std::string get_class();
std::function<void()> &on_destroy();
};
class global_base_t
{
private:
void fini();
bool has_interface(const wl_interface *interface) const;
wl_global *global = nullptr;
protected:
struct data_t
{
wayland::detail::any user_data;
std::atomic<unsigned int> counter{1};
} *data = nullptr;
global_base_t(display_t &display, const wl_interface* interface, int version, data_t *dat, wl_global_bind_func_t func);
public:
global_base_t(wl_global *g);
global_base_t(const global_base_t& g);
global_base_t(global_base_t&& g) noexcept;
~global_base_t();
global_base_t &operator=(const global_base_t& g);
global_base_t &operator=(global_base_t&& g) noexcept;
bool operator==(const global_base_t& g) const;
wl_global *c_ptr() const;
wayland::detail::any &user_data();
template <typename resource>
bool has_interface() // instead if wl_global_get_interface
{
return has_interface(resource::interface);
}
};
template <class resource>
class global_t : public global_base_t
{
private:
struct data_t : public global_base_t::data_t
{
std::function<void(client_t, resource)> bind;
};
static void bind_func(wl_client *cl, void *d, uint32_t ver, uint32_t id)
{
auto *data = reinterpret_cast<data_t*>(d);
client_t client(cl);
resource res(client, ver, id);
if(data->bind)
data->bind(client, res);
}
public:
global_t() = delete;
global_t(display_t &display, unsigned int version = resource::max_version)
: global_base_t(display, resource::interface, version, new data_t, bind_func)
{
}
std::function<void(client_t, resource)> &on_bind()
{
return static_cast<data_t*>(data)->bind;
}
};
struct fd_event_mask_t : public wayland::detail::bitfield<2, -1>
{
fd_event_mask_t(const wayland::detail::bitfield<2, -1> &b)
: wayland::detail::bitfield<2, -1>(b) {}
fd_event_mask_t(const uint32_t value)
: wayland::detail::bitfield<2, -1>(value) {}
static const wayland::detail::bitfield<2, -1> readable;
static const wayland::detail::bitfield<2, -1> writable;
static const wayland::detail::bitfield<2, -1> hangup;
static const wayland::detail::bitfield<2, -1> error;
};
class event_loop_t
{
private:
struct data_t
{
std::function<void()> destroy;
detail::listener_t destroy_listener;
std::list<std::function<int(int, uint32_t)>> fd_funcs;
std::list<std::function<int()>> timer_funcs;
std::list<std::function<int(int)>> signal_funcs;
std::list<std::function<void()>> idle_funcs;
wayland::detail::any user_data;
bool do_delete = true;
std::atomic<unsigned int> counter{1};
};
wl_event_loop *event_loop = nullptr;
data_t *data = nullptr;
static data_t *wl_event_loop_get_user_data(wl_event_loop *client);
static void destroy_func(wl_listener *listener, void *data);
static int event_loop_fd_func(int fd, uint32_t mask, void *data);
static int event_loop_timer_func(void *data);
static int event_loop_signal_func(int signal_number, void *data);
static void event_loop_idle_func(void *data);
protected:
event_loop_t(wl_event_loop *p);
void init();
void fini();
friend class display_t;
public:
event_loop_t();
~event_loop_t();
event_loop_t(const event_loop_t& e);
event_loop_t(event_loop_t&& e) noexcept;
event_loop_t &operator=(const event_loop_t& e);
event_loop_t &operator=(event_loop_t&& e) noexcept;
bool operator==(const event_loop_t& e) const;
wl_event_loop *c_ptr() const;
wayland::detail::any &user_data();
event_source_t add_fd(int fd, const fd_event_mask_t& mask, const std::function<int(int, uint32_t)> &func);
event_source_t add_timer(const std::function<int()> &func);
event_source_t add_signal(int signal_number, const std::function<int(int)> &func);
event_source_t add_idle(const std::function<void()> &func);
const std::function<void()> &on_destroy();
int dispatch(int timeout) const;
void dispatch_idle() const;
int get_fd() const;
};
class event_source_t : public wayland::detail::refcounted_wrapper<wl_event_source>
{
private:
wl_event_source *event_source = nullptr;
protected:
event_source_t(wl_event_source *p);
friend class event_loop_t;
public:
event_source_t() = delete;
wl_event_source *c_ptr() const;
int timer_update(int ms_delay) const;
int fd_update(const fd_event_mask_t& mask) const;
void check() const;
};
}
}
#endif
wayland::detail::refcounted_wrapper
Refcounted wrapper for C objects.
Definition wayland-util.hpp:154
wayland::server::global_base_t
Definition wayland-server.hpp:581
wayland::server::global_base_t::has_interface
bool has_interface()
Definition wayland-server.hpp:614
wayland::server::global_t
Definition wayland-server.hpp:626
wayland::server::global_t::global_t
global_t(display_t &display, unsigned int version=resource::max_version)
Definition wayland-server.hpp:650
wayland::server::global_t::on_bind
std::function< void(client_t, resource)> & on_bind()
Definition wayland-server.hpp:661
wayland::set_log_handler
void set_log_handler(log_handler handler)
Set C library log handler.
wayland::server::log_handler
std::function< void(std::string)> log_handler
Type for functions that handle log messages.
Definition wayland-server.hpp:58