This commit is contained in:
Mars 2025-05-13 01:48:08 -04:00
parent 009556cabf
commit 3d1d344ec1
Signed by: pupbrained
GPG key ID: 0FF5B8826803F895
14 changed files with 383 additions and 196 deletions

View file

@ -23,16 +23,22 @@ ContinuationIndentWidth: 2
Cpp11BracedListStyle: false Cpp11BracedListStyle: false
IncludeBlocks: Regroup IncludeBlocks: Regroup
IncludeCategories: IncludeCategories:
# 1. System headers (<iostream>, <vector>, etc.)
- Regex: '^<.*>$' - Regex: '^<.*>$'
Priority: 1 Priority: 1
# 2. Project headers starting with "src/" - Regex: '^"Config/.*"'
- Regex: '^"src/.*"'
Priority: 2 Priority: 2
# 3. All other quoted headers (including same-directory like "system_data.h") - Regex: '^"Core/.*"'
# This acts as a fallback for quoted includes not matching the above.
- Regex: '^".*"'
Priority: 3 Priority: 3
- Regex: '^"Services/.*"'
Priority: 4
- Regex: '^"UI/.*"'
Priority: 5
- Regex: '^"Util/.*"'
Priority: 6
- Regex: '^"Wrappers/.*"'
Priority: 7
- Regex: '^".*"$'
Priority: 8
IndentExternBlock: Indent IndentExternBlock: Indent
IndentPPDirectives: BeforeHash IndentPPDirectives: BeforeHash
NamespaceIndentation: All NamespaceIndentation: All

View file

@ -1005,9 +1005,7 @@ namespace argparse {
*/ */
template <class F, class... Args> template <class F, class... Args>
fn action(F&& callable, Args&&... bound_args) fn action(F&& callable, Args&&... bound_args)
-> Argument& -> Argument& requires(std::is_invocable_v<F, Args..., const String>) {
requires(std::is_invocable_v<F, Args..., const String>)
{
using RawReturnType = std::invoke_result_t<F, Args..., const String>; using RawReturnType = std::invoke_result_t<F, Args..., const String>;
if constexpr (std::is_void_v<RawReturnType>) { if constexpr (std::is_void_v<RawReturnType>) {
@ -1077,9 +1075,7 @@ namespace argparse {
* @return Reference to this argument for method chaining * @return Reference to this argument for method chaining
*/ */
template <typename T> template <typename T>
fn store_into(T& var) -> Argument& fn store_into(T& var) -> Argument& requires(std::is_integral_v<T>) {
requires(std::is_integral_v<T>)
{
if (m_default_value.has_value()) if (m_default_value.has_value())
var = std::get<T>(m_default_value.value()); var = std::get<T>(m_default_value.value());
@ -1103,9 +1099,7 @@ namespace argparse {
* @return Reference to this argument for method chaining * @return Reference to this argument for method chaining
*/ */
template <typename T> template <typename T>
fn store_into(T& var) -> Argument& fn store_into(T& var)->Argument& requires(std::is_floating_point_v<T>) {
requires(std::is_floating_point_v<T>)
{
if (m_default_value.has_value()) if (m_default_value.has_value())
var = std::get<T>(m_default_value.value()); var = std::get<T>(m_default_value.value());
@ -1291,9 +1285,7 @@ namespace argparse {
* - 'g'/'G': General format * - 'g'/'G': General format
*/ */
template <char Shape, typename T> template <char Shape, typename T>
fn scan() -> Argument& fn scan() -> Argument& requires(std::is_arithmetic_v<T>) {
requires(std::is_arithmetic_v<T>)
{
static_assert(!(std::is_const_v<T> || std::is_volatile_v<T>), "T should not be cv-qualified"); static_assert(!(std::is_const_v<T> || std::is_volatile_v<T>), "T should not be cv-qualified");
fn is_one_of = [](char c, auto... x) constexpr { fn is_one_of = [](char c, auto... x) constexpr {
@ -1574,8 +1566,7 @@ namespace argparse {
if (m_implicit_value.has_value()) if (m_implicit_value.has_value())
m_values.emplace_back(*m_implicit_value); m_values.emplace_back(*m_implicit_value);
for (usize i = 0; i < m_actions.size(); ++i) { for (auto& action : m_actions) {
auto& action = m_actions[i];
Result<> action_call_result; Result<> action_call_result;
std::visit([&](auto& f) { std::visit([&](auto& f) {
if constexpr (std::is_same_v<decltype(f({})), Result<ArgValue>>) { if constexpr (std::is_same_v<decltype(f({})), Result<ArgValue>>) {
@ -1658,8 +1649,7 @@ namespace argparse {
}; };
if (!dry_run) { if (!dry_run) {
for (usize i = 0; i < m_actions.size(); ++i) { for (auto& action : m_actions) {
auto& action = m_actions[i];
Result<> apply_result = std::visit(ActionApply { start, end, *this }, action); Result<> apply_result = std::visit(ActionApply { start, end, *this }, action);
if (!apply_result) if (!apply_result)
return Err(apply_result.error()); return Err(apply_result.error());
@ -2117,7 +2107,7 @@ namespace argparse {
}; };
fn consume_digits = [=](StringView sd) -> StringView { fn consume_digits = [=](StringView sd) -> StringView {
const auto it = std::ranges::find_if_not(sd, is_digit); const auto* const it = std::ranges::find_if_not(sd, is_digit);
return sd.substr(static_cast<usize>(it - std::begin(sd))); return sd.substr(static_cast<usize>(it - std::begin(sd)));
}; };

View file

@ -729,7 +729,8 @@ namespace matchit {
template <typename Unary, typename Pattern> template <typename Unary, typename Pattern>
class App { class App {
public: public:
constexpr App(Unary&& unary, const Pattern& pattern) : mUnary { std::move(unary) }, mPattern { pattern } {} constexpr App(Unary&& unary, const Pattern& pattern)
: mUnary { std::move(unary) }, mPattern { pattern } {}
[[nodiscard]] constexpr fn unary() const -> const Unary& { [[nodiscard]] constexpr fn unary() const -> const Unary& {
return mUnary; return mUnary;
@ -1086,7 +1087,8 @@ namespace matchit {
public: public:
constexpr Id() = default; constexpr Id() = default;
constexpr Id(const Id& id) : mBlock(BlockVT { &id.block() }) {} constexpr Id(const Id& id)
: mBlock(BlockVT { &id.block() }) {}
// non-const to inform users not to mark Id as const. // non-const to inform users not to mark Id as const.
template <typename Pattern> template <typename Pattern>

View file

@ -15,15 +15,17 @@
#include "Util/Env.hpp" #include "Util/Env.hpp"
#endif #endif
#include "../Services/Weather/MetNoService.hpp"
#include "../Services/Weather/OpenMeteoService.hpp"
#include "../Services/Weather/OpenWeatherMapService.hpp"
#include "Services/Weather.hpp" #include "Services/Weather.hpp"
#include "Util/Definitions.hpp" #include "Util/Definitions.hpp"
#include "Util/Error.hpp" #include "Util/Error.hpp"
#include "Util/Logging.hpp" #include "Util/Logging.hpp"
#include "Util/Types.hpp" #include "Util/Types.hpp"
#include "../Services/Weather/MetNoService.hpp"
#include "../Services/Weather/OpenMeteoService.hpp"
#include "../Services/Weather/OpenWeatherMapService.hpp"
using util::error::DracError; using util::error::DracError;
using util::types::CStr, util::types::String, util::types::Array, util::types::Option, util::types::Result; using util::types::CStr, util::types::String, util::types::Array, util::types::Option, util::types::Result;

View file

@ -7,13 +7,16 @@
#include <matchit.hpp> // matchit::{match, is, in, _} #include <matchit.hpp> // matchit::{match, is, in, _}
#include "Config/Config.hpp" #include "Config/Config.hpp"
#include "OS/OperatingSystem.hpp"
#include "Services/PackageCounting.hpp" #include "Services/PackageCounting.hpp"
#include "Services/Weather.hpp" #include "Services/Weather.hpp"
#include "Util/Definitions.hpp" #include "Util/Definitions.hpp"
#include "Util/Error.hpp" #include "Util/Error.hpp"
#include "Util/Types.hpp" #include "Util/Types.hpp"
#include "OS/OperatingSystem.hpp"
using util::error::DracError, util::error::DracErrorCode; using util::error::DracError, util::error::DracErrorCode;
namespace { namespace {

View file

@ -3,6 +3,7 @@
#include <format> // std::{formatter, format_to} #include <format> // std::{formatter, format_to}
#include "Services/Weather.hpp" #include "Services/Weather.hpp"
#include "Util/Definitions.hpp" #include "Util/Definitions.hpp"
#include "Util/Error.hpp" #include "Util/Error.hpp"
#include "Util/Types.hpp" #include "Util/Types.hpp"

View file

@ -21,12 +21,14 @@
#include <utility> // std::move #include <utility> // std::move
#include "Services/PackageCounting.hpp" #include "Services/PackageCounting.hpp"
#include "Util/Caching.hpp" #include "Util/Caching.hpp"
#include "Util/Definitions.hpp" #include "Util/Definitions.hpp"
#include "Util/Env.hpp" #include "Util/Env.hpp"
#include "Util/Error.hpp" #include "Util/Error.hpp"
#include "Util/Logging.hpp" #include "Util/Logging.hpp"
#include "Util/Types.hpp" #include "Util/Types.hpp"
#include "Wrappers/DBus.hpp" #include "Wrappers/DBus.hpp"
#include "Wrappers/Wayland.hpp" #include "Wrappers/Wayland.hpp"
#include "Wrappers/XCB.hpp" #include "Wrappers/XCB.hpp"
@ -40,7 +42,7 @@ using util::types::String, util::types::Result, util::types::Err, util::types::u
namespace { namespace {
#ifdef HAVE_XCB #ifdef HAVE_XCB
fn GetX11WindowManager() -> Result<String> { fn GetX11WindowManager() -> Result<String> {
using namespace xcb; using namespace XCB;
using namespace matchit; using namespace matchit;
using enum ConnError; using enum ConnError;
using util::types::StringView; using util::types::StringView;
@ -65,10 +67,10 @@ namespace {
) )
); );
fn internAtom = [&conn](const StringView name) -> Result<atom_t> { fn internAtom = [&conn](const StringView name) -> Result<Atom> {
using util::types::u16; using util::types::u16;
const ReplyGuard<intern_atom_reply_t> reply(InternAtomReply(conn.get(), InternAtom(conn.get(), 0, static_cast<u16>(name.size()), name.data()), nullptr)); const ReplyGuard<IntAtomReply> reply(InternAtomReply(conn.get(), InternAtom(conn.get(), 0, static_cast<u16>(name.size()), name.data()), nullptr));
if (!reply) if (!reply)
return Err(DracError(DracErrorCode::PlatformSpecific, std::format("Failed to get X11 atom reply for '{}'", name))); return Err(DracError(DracErrorCode::PlatformSpecific, std::format("Failed to get X11 atom reply for '{}'", name)));
@ -76,9 +78,9 @@ namespace {
return reply->atom; return reply->atom;
}; };
const Result<atom_t> supportingWmCheckAtom = internAtom("_NET_SUPPORTING_WM_CHECK"); const Result<Atom> supportingWmCheckAtom = internAtom("_NET_SUPPORTING_WM_CHECK");
const Result<atom_t> wmNameAtom = internAtom("_NET_WM_NAME"); const Result<Atom> wmNameAtom = internAtom("_NET_WM_NAME");
const Result<atom_t> utf8StringAtom = internAtom("UTF8_STRING"); const Result<Atom> utf8StringAtom = internAtom("UTF8_STRING");
if (!supportingWmCheckAtom || !wmNameAtom || !utf8StringAtom) { if (!supportingWmCheckAtom || !wmNameAtom || !utf8StringAtom) {
if (!supportingWmCheckAtom) if (!supportingWmCheckAtom)
@ -93,7 +95,7 @@ namespace {
return Err(DracError(DracErrorCode::PlatformSpecific, "Failed to get X11 atoms")); return Err(DracError(DracErrorCode::PlatformSpecific, "Failed to get X11 atoms"));
} }
const ReplyGuard<get_property_reply_t> wmWindowReply(GetPropertyReply( const ReplyGuard<GetPropReply> wmWindowReply(GetPropertyReply(
conn.get(), conn.get(),
GetProperty(conn.get(), 0, conn.rootScreen()->root, *supportingWmCheckAtom, ATOM_WINDOW, 0, 1), GetProperty(conn.get(), 0, conn.rootScreen()->root, *supportingWmCheckAtom, ATOM_WINDOW, 0, 1),
nullptr nullptr
@ -103,9 +105,9 @@ namespace {
GetPropertyValueLength(wmWindowReply.get()) == 0) GetPropertyValueLength(wmWindowReply.get()) == 0)
return Err(DracError(DracErrorCode::NotFound, "Failed to get _NET_SUPPORTING_WM_CHECK property")); return Err(DracError(DracErrorCode::NotFound, "Failed to get _NET_SUPPORTING_WM_CHECK property"));
const window_t wmRootWindow = *static_cast<window_t*>(GetPropertyValue(wmWindowReply.get())); const Window wmRootWindow = *static_cast<Window*>(GetPropertyValue(wmWindowReply.get()));
const ReplyGuard<get_property_reply_t> wmNameReply(GetPropertyReply( const ReplyGuard<GetPropReply> wmNameReply(GetPropertyReply(
conn.get(), GetProperty(conn.get(), 0, wmRootWindow, *wmNameAtom, *utf8StringAtom, 0, 1024), nullptr conn.get(), GetProperty(conn.get(), 0, wmRootWindow, *wmNameAtom, *utf8StringAtom, 0, 1024), nullptr
)); ));
@ -127,7 +129,7 @@ namespace {
fn GetWaylandCompositor() -> Result<String> { fn GetWaylandCompositor() -> Result<String> {
using util::types::i32, util::types::Array, util::types::isize, util::types::StringView; using util::types::i32, util::types::Array, util::types::isize, util::types::StringView;
const wl::DisplayGuard display; const Wayland::DisplayGuard display;
if (!display) if (!display)
return Err(DracError(DracErrorCode::NotFound, "Failed to connect to display (is Wayland running?)")); return Err(DracError(DracErrorCode::NotFound, "Failed to connect to display (is Wayland running?)"));
@ -226,9 +228,7 @@ namespace os {
value = value.substr(1, value.length() - 2); value = value.substr(1, value.length() - 2);
if (value.empty()) if (value.empty())
return Err( return Err(DracError(DracErrorCode::ParseError, std::format("PRETTY_NAME value is empty or only quotes in /etc/os-release")));
DracError(DracErrorCode::ParseError, std::format("PRETTY_NAME value is empty or only quotes in /etc/os-release"))
);
return value; return value;
} }
@ -257,7 +257,7 @@ namespace os {
fn GetNowPlaying() -> Result<MediaInfo> { fn GetNowPlaying() -> Result<MediaInfo> {
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
using namespace dbus; using namespace DBus;
Result<Connection> connectionResult = Connection::busGet(DBUS_BUS_SESSION); Result<Connection> connectionResult = Connection::busGet(DBUS_BUS_SESSION);
if (!connectionResult) if (!connectionResult)
@ -286,9 +286,7 @@ namespace os {
MessageIter subIter = iter.recurse(); MessageIter subIter = iter.recurse();
if (!subIter.isValid()) if (!subIter.isValid())
return Err( return Err(DracError(DracErrorCode::ParseError, "Invalid DBus ListNames reply format: Could not recurse into array"));
DracError(DracErrorCode::ParseError, "Invalid DBus ListNames reply format: Could not recurse into array")
);
while (subIter.getArgType() != DBUS_TYPE_INVALID) { while (subIter.getArgType() != DBUS_TYPE_INVALID) {
if (Option<String> name = subIter.getString()) if (Option<String> name = subIter.getString())

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "Services/Weather.hpp" #include "Services/Weather.hpp"
#include "Util/Error.hpp" #include "Util/Error.hpp"
namespace weather { namespace weather {

View file

@ -1,8 +1,9 @@
#include "UI.hpp" #include "UI.hpp"
#include "OS/OperatingSystem.hpp"
#include "Util/Types.hpp" #include "Util/Types.hpp"
#include "OS/OperatingSystem.hpp"
namespace ui { namespace ui {
using namespace ftxui; using namespace ftxui;
using namespace util::types; using namespace util::types;

View file

@ -3,8 +3,10 @@
#include <ftxui/dom/elements.hpp> // ftxui::Element #include <ftxui/dom/elements.hpp> // ftxui::Element
#include <ftxui/screen/color.hpp> // ftxui::Color #include <ftxui/screen/color.hpp> // ftxui::Color
#include "Config/Config.hpp"
#include "Core/SystemData.hpp" #include "Core/SystemData.hpp"
#include "Config/Config.hpp"
#include "Util/Types.hpp" #include "Util/Types.hpp"
namespace ui { namespace ui {

View file

@ -14,38 +14,64 @@
#include "Util/Types.hpp" #include "Util/Types.hpp"
// clang-format on // clang-format on
namespace dbus { namespace DBus {
using util::error::DracError, util::error::DracErrorCode; using util::error::DracError, util::error::DracErrorCode;
using util::types::Option, util::types::Result, util::types::Err, util::types::String, util::types::i32, using util::types::Option, util::types::Result, util::types::Err, util::types::String, util::types::i32,
util::types::u32, util::types::None; util::types::u32, util::types::None;
/** /**
* @brief RAII wrapper for DBusError. Automatically initializes and frees. * @brief RAII wrapper for DBusError. Automatically initializes and frees the error.
*/ */
class Error { class Error {
DBusError m_err {}; DBusError m_err {}; ///< The D-Bus error object
bool m_isInitialized = false; bool m_isInitialized = false; ///< Flag indicating if the error is initialized
public: public:
/**
* @brief Constructor
*
* Initializes the D-Bus error object.
*/
Error() Error()
: m_isInitialized(true) { : m_isInitialized(true) {
dbus_error_init(&m_err); dbus_error_init(&m_err);
} }
/**
* @brief Destructor
*
* Frees the D-Bus error object if it was initialized.
*/
~Error() { ~Error() {
if (m_isInitialized) if (m_isInitialized)
dbus_error_free(&m_err); dbus_error_free(&m_err);
} }
// Non-copyable
Error(const Error&) = delete; Error(const Error&) = delete;
fn operator=(const Error&)->Error& = delete; fn operator=(const Error&)->Error& = delete;
/**
* @brief Move constructor
*
* Transfers ownership of the D-Bus error object.
*
* @param other The other Error object to move from
*/
Error(Error&& other) noexcept Error(Error&& other) noexcept
: m_err(other.m_err), m_isInitialized(other.m_isInitialized) { : m_err(other.m_err), m_isInitialized(other.m_isInitialized) {
other.m_isInitialized = false; other.m_isInitialized = false;
dbus_error_init(&other.m_err); dbus_error_init(&other.m_err);
} }
/**
* @brief Move assignment operator
*
* Transfers ownership of the D-Bus error object.
*
* @param other The other Error object to move from
* @return A reference to this object
*/
fn operator=(Error&& other) noexcept -> Error& { fn operator=(Error&& other) noexcept -> Error& {
if (this != &other) { if (this != &other) {
if (m_isInitialized) if (m_isInitialized)
@ -61,8 +87,8 @@ namespace dbus {
} }
/** /**
* @brief Checks if the D-Bus error is set. * @brief Checks if the error is set.
* @return True if an error is set, false otherwise. * @return True if the error is set and initialized, false otherwise.
*/ */
[[nodiscard]] fn isSet() const -> bool { [[nodiscard]] fn isSet() const -> bool {
return m_isInitialized && dbus_error_is_set(&m_err); return m_isInitialized && dbus_error_is_set(&m_err);
@ -91,6 +117,7 @@ namespace dbus {
[[nodiscard]] fn get() -> DBusError* { [[nodiscard]] fn get() -> DBusError* {
return &m_err; return &m_err;
} }
/** /**
* @brief Gets a const pointer to the underlying DBusError. * @brief Gets a const pointer to the underlying DBusError.
* @return Const pointer to the DBusError struct. * @return Const pointer to the DBusError struct.
@ -100,11 +127,11 @@ namespace dbus {
} }
/** /**
* @brief Converts the D-Bus error to a DraconisError. * @brief Converts the D-Bus error to a DracError.
* @param code The DraconisError code to use if the D-Bus error is set. * @param code The DracErrorCode to use if the D-Bus error is set.
* @return A DraconisError representing the D-Bus error, or an internal error if called when no D-Bus error is set. * @return A DracError representing the D-Bus error, or an internal error if called when no D-Bus error is set.
*/ */
[[nodiscard]] fn toDraconisError(const DracErrorCode code = DracErrorCode::PlatformSpecific) const -> DracError { [[nodiscard]] fn toDracError(const DracErrorCode code = DracErrorCode::PlatformSpecific) const -> DracError {
if (isSet()) if (isSet())
return { code, std::format("D-Bus Error: {} ({})", message(), name()) }; return { code, std::format("D-Bus Error: {} ({})", message(), name()) };
@ -113,23 +140,36 @@ namespace dbus {
}; };
/** /**
* @brief RAII wrapper for DBusMessageIter. Encapsulates iterator operations. * @brief RAII wrapper for DBusMessageIter. Automatically frees the iterator.
* Note: This wrapper does *not* own the message, only the iterator state. *
* It's designed to be used within the scope where the MessageGuard is valid. * This class provides a convenient way to manage the lifetime of a D-Bus message iterator.
*/ */
class MessageIter { class MessageIter {
DBusMessageIter m_iter {}; DBusMessageIter m_iter {}; ///< The D-Bus message iterator
bool m_isValid = false; bool m_isValid = false; ///< Flag indicating if the iterator is valid
explicit MessageIter(const DBusMessageIter& iter, const bool isValid)
: m_iter(iter), m_isValid(isValid) {}
// Allows the Message class to access private members of this class.
friend class Message; friend class Message;
/** /**
* @brief Gets the value of a basic-typed argument. * @brief Constructor
* Unsafe: Caller must ensure 'value' points to memory suitable for the actual argument type. *
* @param value Pointer to store the retrieved value. * Initializes the D-Bus message iterator.
*
* @param iter The D-Bus message iterator to wrap
* @param isValid Flag indicating if the iterator is valid
*/
explicit MessageIter(const DBusMessageIter& iter, const bool isValid)
: m_iter(iter), m_isValid(isValid) {}
/**
* @brief Destructor
*
* Frees the D-Bus message iterator if it was initialized.
*
* @param value Pointer to the value to be freed
*
* @note This function is unsafe and should not be called directly.
*/ */
fn getBasic(void* value) -> void { fn getBasic(void* value) -> void {
if (m_isValid) if (m_isValid)
@ -137,10 +177,15 @@ namespace dbus {
} }
public: public:
// Non-copyable
MessageIter(const MessageIter&) = delete; MessageIter(const MessageIter&) = delete;
fn operator=(const MessageIter&)->MessageIter& = delete; fn operator=(const MessageIter&)->MessageIter& = delete;
// Non-movable
MessageIter(MessageIter&&) = delete; MessageIter(MessageIter&&) = delete;
fn operator=(MessageIter&&)->MessageIter& = delete; fn operator=(MessageIter&&)->MessageIter& = delete;
// Destructor
~MessageIter() = default; ~MessageIter() = default;
/** /**
@ -213,23 +258,51 @@ namespace dbus {
* @brief RAII wrapper for DBusMessage. Automatically unrefs. * @brief RAII wrapper for DBusMessage. Automatically unrefs.
*/ */
class Message { class Message {
DBusMessage* m_msg = nullptr; DBusMessage* m_msg = nullptr; ///< The D-Bus message object
public: public:
/**
* @brief Constructor
*
* Initializes the D-Bus message object.
*
* @param msg The D-Bus message object to wrap
*/
explicit Message(DBusMessage* msg = nullptr) explicit Message(DBusMessage* msg = nullptr)
: m_msg(msg) {} : m_msg(msg) {}
/**
* @brief Destructor
*
* Frees the D-Bus message object if it was initialized.
*/
~Message() { ~Message() {
if (m_msg) if (m_msg)
dbus_message_unref(m_msg); dbus_message_unref(m_msg);
} }
// Non-copyable
Message(const Message&) = delete; Message(const Message&) = delete;
fn operator=(const Message&)->Message& = delete; fn operator=(const Message&)->Message& = delete;
/**
* @brief Move constructor
*
* Transfers ownership of the D-Bus message object.
*
* @param other The other Message object to move from
*/
Message(Message&& other) noexcept Message(Message&& other) noexcept
: m_msg(std::exchange(other.m_msg, nullptr)) {} : m_msg(std::exchange(other.m_msg, nullptr)) {}
/**
* @brief Move assignment operator
*
* Transfers ownership of the D-Bus message object.
*
* @param other The other Message object to move from
* @return A reference to this object
*/
fn operator=(Message&& other) noexcept -> Message& { fn operator=(Message&& other) noexcept -> Message& {
if (this != &other) { if (this != &other) {
if (m_msg) if (m_msg)
@ -285,7 +358,7 @@ namespace dbus {
* @param path Object path (e.g., "/org/freedesktop/Notifications"). Must not be null. * @param path Object path (e.g., "/org/freedesktop/Notifications"). Must not be null.
* @param interface Interface name (e.g., "org.freedesktop.Notifications"). Can be null. * @param interface Interface name (e.g., "org.freedesktop.Notifications"). Can be null.
* @param method Method name (e.g., "Notify"). Must not be null. * @param method Method name (e.g., "Notify"). Must not be null.
* @return Result containing a MessageGuard on success, or DraconisError on failure. * @return Result containing a MessageGuard on success, or DracError on failure.
*/ */
static fn newMethodCall(const char* destination, const char* path, const char* interface, const char* method) static fn newMethodCall(const char* destination, const char* path, const char* interface, const char* method)
-> Result<Message> { -> Result<Message> {
@ -298,6 +371,13 @@ namespace dbus {
} }
private: private:
/**
* @brief Appends a single argument to the message.
* @tparam T Type of the argument to append.
* @param iter The D-Bus message iterator.
* @param arg The argument to append.
* @return True if the argument was appended successfully, false otherwise (e.g., allocation error).
*/
template <typename T> template <typename T>
fn appendArgInternal(DBusMessageIter& iter, T&& arg) -> bool { fn appendArgInternal(DBusMessageIter& iter, T&& arg) -> bool {
using DecayedT = std::decay_t<T>; using DecayedT = std::decay_t<T>;
@ -313,26 +393,56 @@ namespace dbus {
}; };
/** /**
* @brief RAII wrapper for DBusConnection. Automatically unrefs. * @brief RAII wrapper for DBusConnection. Automatically unrefs the connection.
*
* This class provides a convenient way to manage the lifetime of a D-Bus connection.
*/ */
class Connection { class Connection {
DBusConnection* m_conn = nullptr; DBusConnection* m_conn = nullptr; ///< The D-Bus connection object
public: public:
/**
* @brief Constructor
*
* Initializes the D-Bus connection object.
*
* @param conn The D-Bus connection object to wrap
*/
explicit Connection(DBusConnection* conn = nullptr) explicit Connection(DBusConnection* conn = nullptr)
: m_conn(conn) {} : m_conn(conn) {}
/**
* @brief Destructor
*
* Frees the D-Bus connection object if it was initialized.
*/
~Connection() { ~Connection() {
if (m_conn) if (m_conn)
dbus_connection_unref(m_conn); dbus_connection_unref(m_conn);
} }
// Non-copyable
Connection(const Connection&) = delete; Connection(const Connection&) = delete;
fn operator=(const Connection&)->Connection& = delete; fn operator=(const Connection&)->Connection& = delete;
/**
* @brief Move constructor
*
* Transfers ownership of the D-Bus connection object.
*
* @param other The other Connection object to move from
*/
Connection(Connection&& other) noexcept Connection(Connection&& other) noexcept
: m_conn(std::exchange(other.m_conn, nullptr)) {} : m_conn(std::exchange(other.m_conn, nullptr)) {}
/**
* @brief Move assignment operator
*
* Transfers ownership of the D-Bus connection object.
*
* @param other The other Connection object to move from
* @return A reference to this object
*/
fn operator=(Connection&& other) noexcept -> Connection& { fn operator=(Connection&& other) noexcept -> Connection& {
if (this != &other) { if (this != &other) {
if (m_conn) if (m_conn)
@ -355,7 +465,7 @@ namespace dbus {
* @brief Sends a message and waits for a reply, blocking execution. * @brief Sends a message and waits for a reply, blocking execution.
* @param message The D-Bus message guard to send. * @param message The D-Bus message guard to send.
* @param timeout_milliseconds Timeout duration in milliseconds. * @param timeout_milliseconds Timeout duration in milliseconds.
* @return Result containing the reply MessageGuard on success, or DraconisError on failure. * @return Result containing the reply MessageGuard on success, or DracError on failure.
*/ */
[[nodiscard]] fn sendWithReplyAndBlock(const Message& message, const i32 timeout_milliseconds = 1000) const [[nodiscard]] fn sendWithReplyAndBlock(const Message& message, const i32 timeout_milliseconds = 1000) const
-> Result<Message> { -> Result<Message> {
@ -371,16 +481,16 @@ namespace dbus {
if (err.isSet()) { if (err.isSet()) {
if (const char* errName = err.name()) { if (const char* errName = err.name()) {
if (strcmp(errName, DBUS_ERROR_TIMEOUT) == 0 || strcmp(errName, DBUS_ERROR_NO_REPLY) == 0) if (strcmp(errName, DBUS_ERROR_TIMEOUT) == 0 || strcmp(errName, DBUS_ERROR_NO_REPLY) == 0)
return Err(err.toDraconisError(DracErrorCode::Timeout)); return Err(err.toDracError(DracErrorCode::Timeout));
if (strcmp(errName, DBUS_ERROR_SERVICE_UNKNOWN) == 0) if (strcmp(errName, DBUS_ERROR_SERVICE_UNKNOWN) == 0)
return Err(err.toDraconisError(DracErrorCode::NotFound)); return Err(err.toDracError(DracErrorCode::NotFound));
if (strcmp(errName, DBUS_ERROR_ACCESS_DENIED) == 0) if (strcmp(errName, DBUS_ERROR_ACCESS_DENIED) == 0)
return Err(err.toDraconisError(DracErrorCode::PermissionDenied)); return Err(err.toDracError(DracErrorCode::PermissionDenied));
} }
return Err(err.toDraconisError(DracErrorCode::PlatformSpecific)); return Err(err.toDracError(DracErrorCode::PlatformSpecific));
} }
if (!rawReply) if (!rawReply)
@ -396,14 +506,14 @@ namespace dbus {
/** /**
* @brief Connects to a D-Bus bus type (Session or System). * @brief Connects to a D-Bus bus type (Session or System).
* @param bus_type The type of bus (DBUS_BUS_SESSION or DBUS_BUS_SYSTEM). * @param bus_type The type of bus (DBUS_BUS_SESSION or DBUS_BUS_SYSTEM).
* @return Result containing a ConnectionGuard on success, or DraconisError on failure. * @return Result containing a ConnectionGuard on success, or DracError on failure.
*/ */
static fn busGet(const DBusBusType bus_type) -> Result<Connection> { static fn busGet(const DBusBusType bus_type) -> Result<Connection> {
Error err; Error err;
DBusConnection* rawConn = dbus_bus_get(bus_type, err.get()); DBusConnection* rawConn = dbus_bus_get(bus_type, err.get());
if (err.isSet()) if (err.isSet())
return Err(err.toDraconisError(DracErrorCode::ApiUnavailable)); return Err(err.toDracError(DracErrorCode::ApiUnavailable));
if (!rawConn) if (!rawConn)
return Err(DracError(DracErrorCode::ApiUnavailable, "dbus_bus_get returned null without setting error")); return Err(DracError(DracErrorCode::ApiUnavailable, "dbus_bus_get returned null without setting error"));
@ -411,6 +521,6 @@ namespace dbus {
return Connection(rawConn); return Connection(rawConn);
} }
}; };
} // namespace dbus } // namespace DBus
#endif // __linux__ || __FreeBSD__ || __DragonFly__ || __NetBSD__ #endif // __linux__ || __FreeBSD__ || __DragonFly__ || __NetBSD__

View file

@ -10,34 +10,66 @@
#include "Util/Types.hpp" #include "Util/Types.hpp"
// clang-format on // clang-format on
struct wl_display; namespace Wayland {
using util::types::i32, util::types::CStr, util::types::None;
namespace wl { using Display = wl_display;
using display = wl_display;
inline fn Connect(const char* name) -> display* { /**
* @brief Connect to a Wayland display
*
* This function establishes a connection to a Wayland display. It takes a
* display name as an argument.
*
* @param name The name of the display to connect to (or nullptr for default)
* @return A pointer to the Wayland display object
*/
inline fn Connect(CStr name) -> Display* {
return wl_display_connect(name); return wl_display_connect(name);
} }
inline fn Disconnect(display* display) -> void {
/**
* @brief Disconnect from a Wayland display
*
* This function disconnects from a Wayland display.
*
* @param display The Wayland display object to disconnect from
* @return void
*/
inline fn Disconnect(Display* display) -> void {
wl_display_disconnect(display); wl_display_disconnect(display);
} }
inline fn GetFd(display* display) -> int {
/**
* @brief Get the file descriptor for a Wayland display
*
* This function retrieves the file descriptor for a Wayland display.
*
* @param display The Wayland display object
* @return The file descriptor for the Wayland display
*/
inline fn GetFd(Display* display) -> i32 {
return wl_display_get_fd(display); return wl_display_get_fd(display);
} }
/** /**
* RAII wrapper for Wayland display connections * @brief RAII wrapper for Wayland display connections
* Automatically handles resource acquisition and cleanup *
* This class manages the connection to a Wayland display. It automatically
* handles resource acquisition and cleanup.
*/ */
class DisplayGuard { class DisplayGuard {
display* m_display; Display* m_display; ///< The Wayland display object
public: public:
/** /**
* Opens a Wayland display connection * @brief Constructor
*
* This constructor sets up a custom logging handler for Wayland and
* establishes a connection to the Wayland display.
*/ */
DisplayGuard() { DisplayGuard() {
wl_log_set_handler_client([](const char* fmt, va_list args) -> void { wl_log_set_handler_client([](CStr fmt, va_list args) -> void {
using util::types::i32, util::types::StringView; using util::types::i32, util::types::StringView;
va_list argsCopy; va_list argsCopy;
@ -71,6 +103,11 @@ namespace wl {
m_display = Connect(nullptr); m_display = Connect(nullptr);
} }
/**
* @brief Destructor
*
* This destructor disconnects from the Wayland display if it is valid.
*/
~DisplayGuard() { ~DisplayGuard() {
if (m_display) if (m_display)
Disconnect(m_display); Disconnect(m_display);
@ -83,6 +120,15 @@ namespace wl {
// Movable // Movable
DisplayGuard(DisplayGuard&& other) noexcept DisplayGuard(DisplayGuard&& other) noexcept
: m_display(std::exchange(other.m_display, nullptr)) {} : m_display(std::exchange(other.m_display, nullptr)) {}
/**
* @brief Move assignment operator
*
* This operator transfers ownership of the Wayland display connection.
*
* @param other The other DisplayGuard object to move from
* @return A reference to this object
*/
fn operator=(DisplayGuard&& other) noexcept -> DisplayGuard& { fn operator=(DisplayGuard&& other) noexcept -> DisplayGuard& {
if (this != &other) { if (this != &other) {
if (m_display) if (m_display)
@ -94,17 +140,40 @@ namespace wl {
return *this; return *this;
} }
/**
* @brief Check if the display guard is valid
*
* This function checks if the display guard is valid (i.e., if it holds a
* valid Wayland display connection).
*
* @return True if the display guard is valid, false otherwise
*/
[[nodiscard]] explicit operator bool() const { [[nodiscard]] explicit operator bool() const {
return m_display != nullptr; return m_display != nullptr;
} }
[[nodiscard]] fn get() const -> display* { /**
* @brief Get the Wayland display connection
*
* This function retrieves the underlying Wayland display connection.
*
* @return The Wayland display connection
*/
[[nodiscard]] fn get() const -> Display* {
return m_display; return m_display;
} }
[[nodiscard]] fn fd() const -> util::types::i32 {
/**
* @brief Get the file descriptor for the Wayland display
*
* This function retrieves the file descriptor for the Wayland display.
*
* @return The file descriptor for the Wayland display
*/
[[nodiscard]] fn fd() const -> i32 {
return GetFd(m_display); return GetFd(m_display);
} }
}; };
} // namespace wl } // namespace Wayland
#endif // __linux__ || __FreeBSD__ || __DragonFly__ || __NetBSD__ #endif // __linux__ || __FreeBSD__ || __DragonFly__ || __NetBSD__

View file

@ -9,22 +9,22 @@
#include "Util/Types.hpp" #include "Util/Types.hpp"
// clang-format on // clang-format on
namespace xcb { namespace XCB {
using util::types::u8, util::types::i32, util::types::CStr, util::types::None; using util::types::u8, util::types::u16, util::types::i32, util::types::u32, util::types::CStr, util::types::None;
using connection_t = xcb_connection_t; using Connection = xcb_connection_t;
using setup_t = xcb_setup_t; using Setup = xcb_setup_t;
using screen_t = xcb_screen_t; using Screen = xcb_screen_t;
using window_t = xcb_window_t; using Window = xcb_window_t;
using atom_t = xcb_atom_t; using Atom = xcb_atom_t;
using generic_error_t = xcb_generic_error_t; using GenericError = xcb_generic_error_t;
using intern_atom_cookie_t = xcb_intern_atom_cookie_t; using IntAtomCookie = xcb_intern_atom_cookie_t;
using intern_atom_reply_t = xcb_intern_atom_reply_t; using IntAtomReply = xcb_intern_atom_reply_t;
using get_property_cookie_t = xcb_get_property_cookie_t; using GetPropCookie = xcb_get_property_cookie_t;
using get_property_reply_t = xcb_get_property_reply_t; using GetPropReply = xcb_get_property_reply_t;
constexpr atom_t ATOM_WINDOW = XCB_ATOM_WINDOW; ///< Window atom constexpr Atom ATOM_WINDOW = XCB_ATOM_WINDOW; ///< Window atom
/** /**
* @brief Enum representing different types of connection errors * @brief Enum representing different types of connection errors
@ -54,7 +54,7 @@ namespace xcb {
* @param screenp Pointer to an integer that will store the screen number * @param screenp Pointer to an integer that will store the screen number
* @return A pointer to the connection object * @return A pointer to the connection object
*/ */
inline fn Connect(const char* displayname, int* screenp) -> connection_t* { inline fn Connect(CStr displayname, i32* screenp) -> Connection* {
return xcb_connect(displayname, screenp); return xcb_connect(displayname, screenp);
} }
@ -66,7 +66,7 @@ namespace xcb {
* *
* @param conn The connection object to disconnect from * @param conn The connection object to disconnect from
*/ */
inline fn Disconnect(connection_t* conn) -> void { inline fn Disconnect(Connection* conn) -> void {
xcb_disconnect(conn); xcb_disconnect(conn);
} }
@ -79,7 +79,7 @@ namespace xcb {
* @param conn The connection object to check * @param conn The connection object to check
* @return 1 if the connection has an error, 0 otherwise * @return 1 if the connection has an error, 0 otherwise
*/ */
inline fn ConnectionHasError(connection_t* conn) -> int { inline fn ConnectionHasError(Connection* conn) -> i32 {
return xcb_connection_has_error(conn); return xcb_connection_has_error(conn);
} }
@ -94,8 +94,7 @@ namespace xcb {
* @param name The name of the atom * @param name The name of the atom
* @return The cookie for the atom * @return The cookie for the atom
*/ */
inline fn InternAtom(connection_t* conn, const uint8_t only_if_exists, const uint16_t name_len, const char* name) inline fn InternAtom(Connection* conn, const u8 only_if_exists, const u16 name_len, CStr name) -> IntAtomCookie {
-> intern_atom_cookie_t {
return xcb_intern_atom(conn, only_if_exists, name_len, name); return xcb_intern_atom(conn, only_if_exists, name_len, name);
} }
@ -110,8 +109,7 @@ namespace xcb {
* @param err The pointer to the generic error * @param err The pointer to the generic error
* @return The reply for the atom * @return The reply for the atom
*/ */
inline fn InternAtomReply(connection_t* conn, const intern_atom_cookie_t cookie, generic_error_t** err) inline fn InternAtomReply(Connection* conn, const IntAtomCookie cookie, GenericError** err) -> IntAtomReply* {
-> intern_atom_reply_t* {
return xcb_intern_atom_reply(conn, cookie, err); return xcb_intern_atom_reply(conn, cookie, err);
} }
@ -128,14 +126,14 @@ namespace xcb {
* @param type The type * @param type The type
*/ */
inline fn GetProperty( inline fn GetProperty(
connection_t* conn, Connection* conn,
const uint8_t _delete, const u8 _delete,
const window_t window, const Window window,
const atom_t property, const Atom property,
const atom_t type, const Atom type,
const uint32_t long_offset, const u32 long_offset,
const uint32_t long_length const u32 long_length
) -> get_property_cookie_t { ) -> GetPropCookie {
return xcb_get_property(conn, _delete, window, property, type, long_offset, long_length); return xcb_get_property(conn, _delete, window, property, type, long_offset, long_length);
} }
@ -150,8 +148,7 @@ namespace xcb {
* @param err The pointer to the generic error * @param err The pointer to the generic error
* @return The reply for the property * @return The reply for the property
*/ */
inline fn GetPropertyReply(connection_t* conn, const get_property_cookie_t cookie, generic_error_t** err) inline fn GetPropertyReply(Connection* conn, const GetPropCookie cookie, GenericError** err) -> GetPropReply* {
-> get_property_reply_t* {
return xcb_get_property_reply(conn, cookie, err); return xcb_get_property_reply(conn, cookie, err);
} }
@ -161,7 +158,7 @@ namespace xcb {
* @param reply The reply for the property * @param reply The reply for the property
* @return The value length for the property * @return The value length for the property
*/ */
inline fn GetPropertyValueLength(const get_property_reply_t* reply) -> int { inline fn GetPropertyValueLength(const GetPropReply* reply) -> i32 {
return xcb_get_property_value_length(reply); return xcb_get_property_value_length(reply);
} }
@ -171,7 +168,7 @@ namespace xcb {
* @param reply The reply for the property * @param reply The reply for the property
* @return The value for the property * @return The value for the property
*/ */
inline fn GetPropertyValue(const get_property_reply_t* reply) -> void* { inline fn GetPropertyValue(const GetPropReply* reply) -> void* {
return xcb_get_property_value(reply); return xcb_get_property_value(reply);
} }
@ -180,15 +177,16 @@ namespace xcb {
* Automatically handles resource acquisition and cleanup * Automatically handles resource acquisition and cleanup
*/ */
class DisplayGuard { class DisplayGuard {
connection_t* m_connection = nullptr; ///< The connection to the display Connection* m_connection = nullptr; ///< The connection to the display
public: public:
/** /**
* Opens an XCB connection * Opens an XCB connection
* @param name Display name (nullptr for default) * @param name Display name (nullptr for default)
*/ */
explicit DisplayGuard(const util::types::CStr name = nullptr) explicit DisplayGuard(const CStr name = nullptr)
: m_connection(Connect(name, nullptr)) {} : m_connection(Connect(name, nullptr)) {}
~DisplayGuard() { ~DisplayGuard() {
if (m_connection) if (m_connection)
Disconnect(m_connection); Disconnect(m_connection);
@ -229,7 +227,7 @@ namespace xcb {
* @brief Get the connection to the display * @brief Get the connection to the display
* @return The connection to the display * @return The connection to the display
*/ */
[[nodiscard]] fn get() const -> connection_t* { [[nodiscard]] fn get() const -> Connection* {
return m_connection; return m_connection;
} }
@ -237,7 +235,7 @@ namespace xcb {
* @brief Get the setup for the display * @brief Get the setup for the display
* @return The setup for the display * @return The setup for the display
*/ */
[[nodiscard]] fn setup() const -> const setup_t* { [[nodiscard]] fn setup() const -> const Setup* {
return m_connection ? xcb_get_setup(m_connection) : nullptr; return m_connection ? xcb_get_setup(m_connection) : nullptr;
} }
@ -245,8 +243,9 @@ namespace xcb {
* @brief Get the root screen for the display * @brief Get the root screen for the display
* @return The root screen for the display * @return The root screen for the display
*/ */
[[nodiscard]] fn rootScreen() const -> screen_t* { [[nodiscard]] fn rootScreen() const -> Screen* {
const setup_t* setup = this->setup(); const Setup* setup = this->setup();
return setup ? xcb_setup_roots_iterator(setup).data : nullptr; return setup ? xcb_setup_roots_iterator(setup).data : nullptr;
} }
}; };
@ -335,6 +334,6 @@ namespace xcb {
return *m_reply; return *m_reply;
} }
}; };
} // namespace xcb } // namespace XCB
#endif // __linux__ || __FreeBSD__ || __DragonFly__ || __NetBSD__ #endif // __linux__ || __FreeBSD__ || __DragonFly__ || __NetBSD__

View file

@ -10,9 +10,12 @@
#include <iostream> // std::cout #include <iostream> // std::cout
#endif #endif
#include "Config/Config.hpp"
#include "Core/SystemData.hpp" #include "Core/SystemData.hpp"
#include "Config/Config.hpp"
#include "UI/UI.hpp" #include "UI/UI.hpp"
#include "Util/Definitions.hpp" #include "Util/Definitions.hpp"
#include "Util/Logging.hpp" #include "Util/Logging.hpp"
#include "Util/Types.hpp" #include "Util/Types.hpp"