198 lines
6.2 KiB
C++
198 lines
6.2 KiB
C++
#pragma once
|
|
|
|
#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
|
|
|
// clang-format off
|
|
#include <xcb/xcb.h> // XCB library
|
|
|
|
#include "src/util/defs.hpp"
|
|
#include "src/util/types.hpp"
|
|
// clang-format on
|
|
|
|
namespace xcb {
|
|
using util::types::u8, util::types::i32, util::types::CStr, util::types::None;
|
|
|
|
using connection_t = xcb_connection_t;
|
|
using setup_t = xcb_setup_t;
|
|
using screen_t = xcb_screen_t;
|
|
using window_t = xcb_window_t;
|
|
using atom_t = xcb_atom_t;
|
|
|
|
using generic_error_t = xcb_generic_error_t;
|
|
using intern_atom_cookie_t = xcb_intern_atom_cookie_t;
|
|
using intern_atom_reply_t = xcb_intern_atom_reply_t;
|
|
using get_property_cookie_t = xcb_get_property_cookie_t;
|
|
using get_property_reply_t = xcb_get_property_reply_t;
|
|
|
|
constexpr atom_t ATOM_WINDOW = XCB_ATOM_WINDOW;
|
|
|
|
enum ConnError : u8 {
|
|
Generic = XCB_CONN_ERROR,
|
|
ExtNotSupported = XCB_CONN_CLOSED_EXT_NOTSUPPORTED,
|
|
MemInsufficient = XCB_CONN_CLOSED_MEM_INSUFFICIENT,
|
|
ReqLenExceed = XCB_CONN_CLOSED_REQ_LEN_EXCEED,
|
|
ParseErr = XCB_CONN_CLOSED_PARSE_ERR,
|
|
InvalidScreen = XCB_CONN_CLOSED_INVALID_SCREEN,
|
|
FdPassingFailed = XCB_CONN_CLOSED_FDPASSING_FAILED,
|
|
};
|
|
|
|
// NOLINTBEGIN(readability-identifier-naming)
|
|
inline fn getConnError(const util::types::i32 code) -> util::types::Option<ConnError> {
|
|
switch (code) {
|
|
case XCB_CONN_ERROR: return Generic;
|
|
case XCB_CONN_CLOSED_EXT_NOTSUPPORTED: return ExtNotSupported;
|
|
case XCB_CONN_CLOSED_MEM_INSUFFICIENT: return MemInsufficient;
|
|
case XCB_CONN_CLOSED_REQ_LEN_EXCEED: return ReqLenExceed;
|
|
case XCB_CONN_CLOSED_PARSE_ERR: return ParseErr;
|
|
case XCB_CONN_CLOSED_INVALID_SCREEN: return InvalidScreen;
|
|
case XCB_CONN_CLOSED_FDPASSING_FAILED: return FdPassingFailed;
|
|
default: return None;
|
|
}
|
|
}
|
|
|
|
inline fn connect(const char* displayname, int* screenp) -> connection_t* {
|
|
return xcb_connect(displayname, screenp);
|
|
}
|
|
inline fn disconnect(connection_t* conn) -> void {
|
|
xcb_disconnect(conn);
|
|
}
|
|
inline fn connection_has_error(connection_t* conn) -> int {
|
|
return xcb_connection_has_error(conn);
|
|
}
|
|
inline fn intern_atom(connection_t* conn, const uint8_t only_if_exists, const uint16_t name_len, const char* name)
|
|
-> intern_atom_cookie_t {
|
|
return xcb_intern_atom(conn, only_if_exists, name_len, name);
|
|
}
|
|
inline fn intern_atom_reply(connection_t* conn, const intern_atom_cookie_t cookie, generic_error_t** err)
|
|
-> intern_atom_reply_t* {
|
|
return xcb_intern_atom_reply(conn, cookie, err);
|
|
}
|
|
inline fn get_property(
|
|
connection_t* conn,
|
|
const uint8_t _delete,
|
|
const window_t window,
|
|
const atom_t property,
|
|
const atom_t type,
|
|
const uint32_t long_offset,
|
|
const uint32_t long_length
|
|
) -> get_property_cookie_t {
|
|
return xcb_get_property(conn, _delete, window, property, type, long_offset, long_length);
|
|
}
|
|
inline fn get_property_reply(connection_t* conn, const get_property_cookie_t cookie, generic_error_t** err)
|
|
-> get_property_reply_t* {
|
|
return xcb_get_property_reply(conn, cookie, err);
|
|
}
|
|
inline fn get_property_value_length(const get_property_reply_t* reply) -> int {
|
|
return xcb_get_property_value_length(reply);
|
|
}
|
|
inline fn get_property_value(const get_property_reply_t* reply) -> void* {
|
|
return xcb_get_property_value(reply);
|
|
}
|
|
// NOLINTEND(readability-identifier-naming)
|
|
|
|
/**
|
|
* RAII wrapper for X11 Display connections
|
|
* Automatically handles resource acquisition and cleanup
|
|
*/
|
|
class DisplayGuard {
|
|
connection_t* m_connection = nullptr;
|
|
|
|
public:
|
|
/**
|
|
* Opens an XCB connection
|
|
* @param name Display name (nullptr for default)
|
|
*/
|
|
explicit DisplayGuard(const util::types::CStr name = nullptr)
|
|
: m_connection(connect(name, nullptr)) {}
|
|
~DisplayGuard() {
|
|
if (m_connection)
|
|
disconnect(m_connection);
|
|
}
|
|
|
|
// Non-copyable
|
|
DisplayGuard(const DisplayGuard&) = delete;
|
|
fn operator=(const DisplayGuard&)->DisplayGuard& = delete;
|
|
|
|
// Movable
|
|
DisplayGuard(DisplayGuard&& other) noexcept
|
|
: m_connection(std::exchange(other.m_connection, nullptr)) {}
|
|
fn operator=(DisplayGuard&& other) noexcept -> DisplayGuard& {
|
|
if (this != &other) {
|
|
if (m_connection)
|
|
disconnect(m_connection);
|
|
|
|
m_connection = std::exchange(other.m_connection, nullptr);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
[[nodiscard]] explicit operator bool() const {
|
|
return m_connection && !connection_has_error(m_connection);
|
|
}
|
|
|
|
[[nodiscard]] fn get() const -> connection_t* {
|
|
return m_connection;
|
|
}
|
|
|
|
[[nodiscard]] fn setup() const -> const setup_t* {
|
|
return m_connection ? xcb_get_setup(m_connection) : nullptr;
|
|
}
|
|
|
|
[[nodiscard]] fn rootScreen() const -> screen_t* {
|
|
const setup_t* setup = this->setup();
|
|
return setup ? xcb_setup_roots_iterator(setup).data : nullptr;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* RAII wrapper for XCB replies
|
|
* Handles automatic cleanup of various XCB reply objects
|
|
*/
|
|
template <typename T>
|
|
class ReplyGuard {
|
|
T* m_reply = nullptr;
|
|
|
|
public:
|
|
ReplyGuard() = default;
|
|
explicit ReplyGuard(T* reply)
|
|
: m_reply(reply) {}
|
|
|
|
~ReplyGuard() {
|
|
if (m_reply)
|
|
free(m_reply);
|
|
}
|
|
|
|
// Non-copyable
|
|
ReplyGuard(const ReplyGuard&) = delete;
|
|
fn operator=(const ReplyGuard&)->ReplyGuard& = delete;
|
|
|
|
// Movable
|
|
ReplyGuard(ReplyGuard&& other) noexcept
|
|
: m_reply(std::exchange(other.m_reply, nullptr)) {}
|
|
fn operator=(ReplyGuard&& other) noexcept -> ReplyGuard& {
|
|
if (this != &other) {
|
|
if (m_reply)
|
|
free(m_reply);
|
|
|
|
m_reply = std::exchange(other.m_reply, nullptr);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
[[nodiscard]] explicit operator bool() const {
|
|
return m_reply != nullptr;
|
|
}
|
|
|
|
[[nodiscard]] fn get() const -> T* {
|
|
return m_reply;
|
|
}
|
|
[[nodiscard]] fn operator->() const->T* {
|
|
return m_reply;
|
|
}
|
|
[[nodiscard]] fn operator*() const->T& {
|
|
return *m_reply;
|
|
}
|
|
};
|
|
} // namespace xcb
|
|
|
|
#endif // __linux__ || __FreeBSD__ || __DragonFly__ || __NetBSD__
|