mirror of
https://github.com/slendidev/lunar.git
synced 2026-01-30 16:28:58 +02:00
Add useful wayland RAII wrappers
Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
@@ -539,6 +539,8 @@ Application::Application()
|
||||
|
||||
init_input();
|
||||
|
||||
init_wayland();
|
||||
|
||||
if (m_backend == Backend::SDL)
|
||||
mouse_captured(true);
|
||||
|
||||
@@ -647,6 +649,15 @@ auto Application::init_test_meshes() -> void
|
||||
m_test_meshes = std::move(*meshes);
|
||||
}
|
||||
|
||||
auto Application::init_wayland() -> void
|
||||
{
|
||||
// TODO: Replace with new name, we might have conflicts!
|
||||
auto const *WAYLAND_SOCKET_NAME { "wayland-5" };
|
||||
m_wayland.display.add_socket(WAYLAND_SOCKET_NAME);
|
||||
assert(setenv("WAYLAND_DISPLAY", WAYLAND_SOCKET_NAME, true) == 0);
|
||||
m_logger.info("Started Wayland display socket on {}", WAYLAND_SOCKET_NAME);
|
||||
}
|
||||
|
||||
auto Application::run() -> void
|
||||
|
||||
{
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL3/SDL_video.h>
|
||||
@@ -19,6 +18,7 @@
|
||||
#include "Logger.h"
|
||||
#include "Skybox.h"
|
||||
#include "Types.h"
|
||||
#include "wayland/Display.h"
|
||||
|
||||
struct libinput;
|
||||
struct libinput_event_keyboard;
|
||||
@@ -55,6 +55,7 @@ private:
|
||||
|
||||
auto init_input() -> void;
|
||||
auto init_test_meshes() -> void;
|
||||
auto init_wayland() -> void;
|
||||
auto asset_directory() -> std::filesystem::path;
|
||||
auto shutdown_input() -> void;
|
||||
auto process_libinput_events() -> void;
|
||||
@@ -79,6 +80,10 @@ private:
|
||||
auto render_hands(
|
||||
VulkanRenderer::GL &gl, smath::Mat4 const &view_projection) -> void;
|
||||
|
||||
struct {
|
||||
Wayland::Display display;
|
||||
} m_wayland;
|
||||
|
||||
SDL_Window *m_window { nullptr };
|
||||
Backend m_backend { Backend::SDL };
|
||||
Logger m_logger { "Lunar" };
|
||||
|
||||
112
src/wayland/Client.h
Normal file
112
src/wayland/Client.h
Normal file
@@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <format>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
#include "Display.h"
|
||||
|
||||
namespace Lunar::Wayland {
|
||||
|
||||
struct Client {
|
||||
Client(wl_client *client)
|
||||
: m_client { std::move(client) }
|
||||
{
|
||||
assert(m_client);
|
||||
}
|
||||
~Client() = default;
|
||||
|
||||
inline auto c_ptr() const -> wl_client * { return m_client; }
|
||||
|
||||
static auto from_link(wl_list *link) -> Client
|
||||
{
|
||||
return Client { wl_client_from_link(link) };
|
||||
}
|
||||
|
||||
auto flush() { wl_client_flush(m_client); }
|
||||
|
||||
auto get_display() -> Display
|
||||
{
|
||||
return Display { wl_client_get_display(m_client) };
|
||||
}
|
||||
|
||||
auto get_credentials() noexcept -> std::tuple<pid_t, uid_t, gid_t>
|
||||
{
|
||||
std::tuple<pid_t, uid_t, gid_t> ret {};
|
||||
auto &[pid, uid, gid] { ret };
|
||||
wl_client_get_credentials(m_client, &pid, &uid, &gid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto get_fd() noexcept -> int { return wl_client_get_fd(m_client); }
|
||||
|
||||
auto get_object(uint32_t id) -> std::optional<wl_resource *>
|
||||
{
|
||||
if (auto *res = wl_client_get_object(m_client, id); res != NULL) {
|
||||
return res;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
auto post_implementation_error(std::string_view string)
|
||||
{
|
||||
wl_client_post_implementation_error(
|
||||
m_client, "%.*s", static_cast<int>(string.size()), string.data());
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto post_implementation_error(
|
||||
std::format_string<Args...> fmt, Args &&...args)
|
||||
{
|
||||
post_implementation_error(
|
||||
std::format(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
auto add_destroy_listener(wl_listener *listener)
|
||||
{
|
||||
wl_client_add_destroy_listener(m_client, listener);
|
||||
}
|
||||
|
||||
auto add_destroy_late_listener(wl_listener *listener)
|
||||
{
|
||||
wl_client_add_destroy_late_listener(m_client, listener);
|
||||
}
|
||||
|
||||
auto get_link() -> List { return wl_client_get_link(m_client); }
|
||||
|
||||
auto add_resource_created_listener(wl_listener *listener)
|
||||
{
|
||||
wl_client_add_resource_created_listener(m_client, listener);
|
||||
}
|
||||
|
||||
auto for_each_resource(
|
||||
std::function<wl_iterator_result(wl_resource *)> const &fn) -> void
|
||||
{
|
||||
wl_client_for_each_resource(
|
||||
m_client,
|
||||
(wl_client_for_each_resource_iterator_func_t)[](
|
||||
wl_resource * res, void *user_data)
|
||||
->wl_iterator_result {
|
||||
auto *f = static_cast<
|
||||
std::function<wl_iterator_result(wl_resource *)> *>(
|
||||
user_data);
|
||||
return (*f)(res);
|
||||
},
|
||||
&fn);
|
||||
}
|
||||
|
||||
auto set_max_buffer_size(size_t max_buffer_size)
|
||||
{
|
||||
wl_client_set_max_buffer_size(m_client, max_buffer_size);
|
||||
}
|
||||
|
||||
private:
|
||||
wl_client *m_client {};
|
||||
};
|
||||
|
||||
} // namespace Lunar::Wayland
|
||||
103
src/wayland/Display.h
Normal file
103
src/wayland/Display.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <format>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
namespace Lunar::Wayland {
|
||||
|
||||
struct Display {
|
||||
Display()
|
||||
: m_display(wl_display_create())
|
||||
{
|
||||
}
|
||||
Display(wl_display *display)
|
||||
: m_display { std::move(display) }
|
||||
, m_should_cleanup { false }
|
||||
{
|
||||
}
|
||||
~Display()
|
||||
{
|
||||
if (!m_should_cleanup)
|
||||
return;
|
||||
wl_display_destroy_clients(m_display);
|
||||
wl_display_destroy(m_display);
|
||||
}
|
||||
|
||||
inline auto c_ptr() const -> wl_display * { return m_display; }
|
||||
|
||||
auto set_global_filter(
|
||||
wl_display_global_filter_func_t filter, void *data) noexcept
|
||||
{
|
||||
wl_display_set_global_filter(m_display, filter, data);
|
||||
}
|
||||
|
||||
auto next_serial() noexcept -> uint32_t
|
||||
{
|
||||
return wl_display_next_serial(m_display);
|
||||
}
|
||||
|
||||
auto set_default_max_buffer_size(size_t max_buffer_size) noexcept
|
||||
{
|
||||
wl_display_set_default_max_buffer_size(m_display, max_buffer_size);
|
||||
}
|
||||
|
||||
auto add_socket_fd(int fd)
|
||||
{
|
||||
if (wl_display_add_socket_fd(m_display, fd) == -1) {
|
||||
throw std::runtime_error(
|
||||
"Failed to add socket fd to Wayland display");
|
||||
}
|
||||
}
|
||||
|
||||
auto add_socket(char const *name)
|
||||
{
|
||||
if (wl_display_add_socket(m_display, name) == -1) {
|
||||
throw std::runtime_error(std::format(
|
||||
"Failed to add socket `{}` to Wayland display", name));
|
||||
}
|
||||
}
|
||||
|
||||
auto add_protocol_logger(wl_protocol_logger_func_t func, void *user_data)
|
||||
-> wl_protocol_logger *
|
||||
{
|
||||
if (auto *logger
|
||||
= wl_display_add_protocol_logger(m_display, func, user_data);
|
||||
logger != NULL) {
|
||||
return logger;
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"Failed to add protocol logger to Wayland display");
|
||||
}
|
||||
}
|
||||
|
||||
auto add_shm_format(uint32_t format) -> uint32_t *
|
||||
{
|
||||
if (auto *fmt = wl_display_add_shm_format(m_display, format);
|
||||
fmt != NULL) {
|
||||
return fmt;
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"Failed to add SHM format to Wayland display");
|
||||
}
|
||||
}
|
||||
|
||||
auto get_client_list() -> std::vector<wl_client *>
|
||||
{
|
||||
std::vector<wl_client *> ret {};
|
||||
auto const list { wl_display_get_client_list(m_display) };
|
||||
assert(list);
|
||||
wl_client *client {};
|
||||
wl_client_for_each(client, list) { ret.push_back(client); }
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
wl_display *m_display {};
|
||||
bool m_should_cleanup { true };
|
||||
};
|
||||
|
||||
} // namespace Lunar::Wayland
|
||||
71
src/wayland/Global.h
Normal file
71
src/wayland/Global.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
#include "Client.h"
|
||||
#include "Display.h"
|
||||
|
||||
namespace Lunar::Wayland {
|
||||
|
||||
struct Global {
|
||||
Global() = delete;
|
||||
|
||||
explicit Global(Display &display, wl_interface const *interface,
|
||||
int version, void *data, wl_global_bind_func_t bind)
|
||||
: m_global {
|
||||
wl_global_create(display.c_ptr(), interface, version, data, bind),
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
Global(wl_global *global)
|
||||
: m_global { std::move(global) }
|
||||
, m_should_cleanup { false }
|
||||
{
|
||||
assert(m_global);
|
||||
}
|
||||
|
||||
~Global()
|
||||
{
|
||||
if (!m_should_cleanup)
|
||||
return;
|
||||
wl_global_destroy(m_global);
|
||||
}
|
||||
|
||||
inline auto c_ptr() const -> wl_global * { return m_global; }
|
||||
|
||||
auto get_name(Client &client) const -> std::optional<uint32_t>
|
||||
{
|
||||
if (auto const ret = wl_global_get_name(m_global, client.c_ptr());
|
||||
ret != 0) {
|
||||
return ret;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
inline auto get_version() const -> uint32_t
|
||||
{
|
||||
return wl_global_get_version(m_global);
|
||||
}
|
||||
|
||||
inline auto get_display() const -> Display
|
||||
{
|
||||
return wl_global_get_display(m_global);
|
||||
}
|
||||
|
||||
inline auto get_interface() const -> wl_interface const *
|
||||
{
|
||||
return wl_global_get_interface(m_global);
|
||||
}
|
||||
|
||||
private:
|
||||
wl_global *m_global {};
|
||||
bool m_should_cleanup { true };
|
||||
};
|
||||
|
||||
} // namespace Lunar::Wayland
|
||||
286
src/wayland/List.h
Normal file
286
src/wayland/List.h
Normal file
@@ -0,0 +1,286 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
namespace Lunar::Wayland {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T, wl_list T::*Member>
|
||||
constexpr std::ptrdiff_t member_offset() noexcept
|
||||
{
|
||||
return reinterpret_cast<std::ptrdiff_t>(
|
||||
&(reinterpret_cast<T const volatile *>(0)->*Member));
|
||||
}
|
||||
|
||||
template<typename T, wl_list T::*Member>
|
||||
inline T *container_of(wl_list *node) noexcept
|
||||
{
|
||||
auto *p = reinterpret_cast<std::byte *>(node) - member_offset<T, Member>();
|
||||
return reinterpret_cast<T *>(p);
|
||||
}
|
||||
|
||||
template<typename T, wl_list T::*Member>
|
||||
inline T const *container_of(wl_list const *node) noexcept
|
||||
{
|
||||
auto *p = reinterpret_cast<std::byte const *>(node)
|
||||
- member_offset<T, Member>();
|
||||
return reinterpret_cast<T const *>(p);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, wl_list T::*Member> struct List {
|
||||
struct Iterator {
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = T;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = T *;
|
||||
using reference = T &;
|
||||
|
||||
Iterator() = default;
|
||||
Iterator(wl_list *cur, wl_list *head)
|
||||
: m_cur(cur)
|
||||
, m_head(head)
|
||||
{
|
||||
}
|
||||
|
||||
auto operator*() const -> reference
|
||||
{
|
||||
return *detail::container_of<T, Member>(m_cur);
|
||||
}
|
||||
auto operator->() const -> pointer
|
||||
{
|
||||
return detail::container_of<T, Member>(m_cur);
|
||||
}
|
||||
|
||||
auto operator++() -> Iterator &
|
||||
{
|
||||
m_cur = m_cur->next;
|
||||
return *this;
|
||||
}
|
||||
auto operator++(int) -> Iterator
|
||||
{
|
||||
auto t = *this;
|
||||
++(*this);
|
||||
return t;
|
||||
}
|
||||
|
||||
auto operator--() -> Iterator &
|
||||
{
|
||||
m_cur = (m_cur == m_head) ? m_head->prev : m_cur->prev;
|
||||
return *this;
|
||||
}
|
||||
auto operator--(int) -> Iterator
|
||||
{
|
||||
auto t = *this;
|
||||
--(*this);
|
||||
return t;
|
||||
}
|
||||
|
||||
friend auto operator==(Iterator a, Iterator b) -> bool
|
||||
{
|
||||
return a.m_cur == b.m_cur;
|
||||
}
|
||||
friend auto operator!=(Iterator a, Iterator b) -> bool
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
private:
|
||||
wl_list *m_cur { nullptr };
|
||||
wl_list *m_head { nullptr };
|
||||
};
|
||||
|
||||
struct ConstIterator {
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = T const;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = T const *;
|
||||
using reference = T const &;
|
||||
|
||||
ConstIterator() = default;
|
||||
ConstIterator(wl_list const *cur, wl_list const *head)
|
||||
: m_cur(cur)
|
||||
, m_head(head)
|
||||
{
|
||||
}
|
||||
|
||||
auto operator*() const -> reference
|
||||
{
|
||||
return *detail::container_of<T, Member>(m_cur);
|
||||
}
|
||||
auto operator->() const -> pointer
|
||||
{
|
||||
return detail::container_of<T, Member>(m_cur);
|
||||
}
|
||||
|
||||
auto operator++() -> ConstIterator &
|
||||
{
|
||||
m_cur = m_cur->next;
|
||||
return *this;
|
||||
}
|
||||
auto operator++(int) -> ConstIterator
|
||||
{
|
||||
auto t = *this;
|
||||
++(*this);
|
||||
return t;
|
||||
}
|
||||
|
||||
auto operator--() -> ConstIterator &
|
||||
{
|
||||
m_cur = (m_cur == m_head) ? m_head->prev : m_cur->prev;
|
||||
return *this;
|
||||
}
|
||||
auto operator--(int) -> ConstIterator
|
||||
{
|
||||
auto t = *this;
|
||||
--(*this);
|
||||
return t;
|
||||
}
|
||||
|
||||
friend auto operator==(ConstIterator a, ConstIterator b) -> bool
|
||||
{
|
||||
return a.m_cur == b.m_cur;
|
||||
}
|
||||
friend auto operator!=(ConstIterator a, ConstIterator b) -> bool
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
private:
|
||||
wl_list const *m_cur { nullptr };
|
||||
wl_list const *m_head { nullptr };
|
||||
};
|
||||
|
||||
List()
|
||||
: m_head {}
|
||||
, m_external_head { nullptr }
|
||||
, m_should_cleanup { true }
|
||||
{
|
||||
wl_list_init(&m_head);
|
||||
}
|
||||
|
||||
explicit List(
|
||||
wl_list *existing_head, bool should_cleanup = false, bool init = false)
|
||||
: m_head {}
|
||||
, m_external_head { existing_head }
|
||||
, m_should_cleanup { should_cleanup }
|
||||
{
|
||||
if (init && m_external_head)
|
||||
wl_list_init(m_external_head);
|
||||
}
|
||||
|
||||
~List()
|
||||
{
|
||||
if (!m_should_cleanup)
|
||||
return;
|
||||
|
||||
clear();
|
||||
if (auto *h = head_ptr(); h)
|
||||
wl_list_init(h);
|
||||
}
|
||||
|
||||
List(List const &) = delete;
|
||||
auto operator=(List const &) -> List & = delete;
|
||||
|
||||
List(List &&other) noexcept { move_from(other); }
|
||||
|
||||
auto operator=(List &&other) noexcept -> List &
|
||||
{
|
||||
if (this != &other) {
|
||||
this->~List();
|
||||
move_from(other);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline auto c_ptr() -> wl_list * { return head_ptr(); }
|
||||
inline auto c_ptr() const -> wl_list const * { return head_ptr(); }
|
||||
|
||||
auto empty() const noexcept -> bool { return wl_list_empty(head_ptr()); }
|
||||
auto length() const noexcept -> int { return wl_list_length(head_ptr()); }
|
||||
|
||||
auto push_front(T *elem) noexcept -> void
|
||||
{
|
||||
wl_list_insert(head_ptr(), &(elem->*Member));
|
||||
}
|
||||
|
||||
auto push_back(T *elem) noexcept -> void
|
||||
{
|
||||
auto *h = head_ptr();
|
||||
wl_list_insert(h->prev, &(elem->*Member));
|
||||
}
|
||||
|
||||
auto remove(T *elem) noexcept -> void
|
||||
{
|
||||
wl_list_remove(&(elem->*Member));
|
||||
wl_list_init(&(elem->*Member));
|
||||
}
|
||||
|
||||
auto clear() noexcept -> void
|
||||
{
|
||||
auto *h = head_ptr();
|
||||
while (!wl_list_empty(h)) {
|
||||
auto *node = h->next;
|
||||
wl_list_remove(node);
|
||||
wl_list_init(node);
|
||||
}
|
||||
}
|
||||
|
||||
auto begin() noexcept -> Iterator
|
||||
{
|
||||
auto *h = head_ptr();
|
||||
return Iterator(h->next, h);
|
||||
}
|
||||
|
||||
auto end() noexcept -> Iterator
|
||||
{
|
||||
auto *h = head_ptr();
|
||||
return Iterator(h, h);
|
||||
}
|
||||
|
||||
auto begin() const noexcept -> ConstIterator
|
||||
{
|
||||
auto const *h = head_ptr();
|
||||
return ConstIterator(h->next, h);
|
||||
}
|
||||
|
||||
auto end() const noexcept -> ConstIterator
|
||||
{
|
||||
auto const *h = head_ptr();
|
||||
return ConstIterator(h, h);
|
||||
}
|
||||
|
||||
private:
|
||||
auto head_ptr() noexcept -> wl_list *
|
||||
{
|
||||
return m_external_head ? m_external_head : &m_head;
|
||||
}
|
||||
|
||||
auto head_ptr() const noexcept -> wl_list const *
|
||||
{
|
||||
return m_external_head ? m_external_head : &m_head;
|
||||
}
|
||||
|
||||
auto move_from(List &other) noexcept -> void
|
||||
{
|
||||
m_head = other.m_head;
|
||||
m_external_head = other.m_external_head;
|
||||
m_should_cleanup = other.m_should_cleanup;
|
||||
|
||||
other.m_external_head = nullptr;
|
||||
other.m_should_cleanup = false;
|
||||
wl_list_init(&other.m_head);
|
||||
}
|
||||
|
||||
private:
|
||||
wl_list m_head {};
|
||||
wl_list *m_external_head { nullptr };
|
||||
bool m_should_cleanup { true };
|
||||
};
|
||||
|
||||
} // namespace Lunar::Wayland
|
||||
28
src/wayland/Signal.h
Normal file
28
src/wayland/Signal.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
namespace Lunar::Wayland {
|
||||
|
||||
struct Signal {
|
||||
Signal(wl_signal *signal)
|
||||
: m_signal { std::move(signal) }
|
||||
{
|
||||
assert(m_signal);
|
||||
}
|
||||
~Signal() = default;
|
||||
|
||||
inline auto c_ptr() const -> wl_signal * { return m_signal; }
|
||||
|
||||
template<typename T = void> auto flush(T *data)
|
||||
{
|
||||
wl_signal_emit_mutable(m_signal, (void *)data);
|
||||
}
|
||||
|
||||
private:
|
||||
wl_signal *m_signal {};
|
||||
};
|
||||
|
||||
} // namespace Lunar::Wayland
|
||||
Reference in New Issue
Block a user