#pragma once #ifdef __linux__ // clang-format off #include // XCB library #include "src/core/util/defs.hpp" #include "src/core/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 { 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 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__