more stuffs
This commit is contained in:
parent
801a8d1754
commit
55819ebfe0
10 changed files with 410 additions and 237 deletions
106
src/os/linux.cpp
106
src/os/linux.cpp
|
@ -3,8 +3,7 @@
|
|||
// clang-format off
|
||||
#include <dbus-cxx.h> // needs to be at top for Success/None
|
||||
// clang-format on
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <ranges>
|
||||
#include <sys/socket.h>
|
||||
|
@ -13,6 +12,7 @@
|
|||
#include <sys/utsname.h>
|
||||
#include <system_error>
|
||||
#include <wayland-client.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "src/os/linux/display_guards.h"
|
||||
|
@ -22,77 +22,69 @@ namespace fs = std::filesystem;
|
|||
using namespace std::string_view_literals;
|
||||
|
||||
namespace {
|
||||
using os::linux::DisplayGuard;
|
||||
using os::linux::WaylandDisplayGuard;
|
||||
|
||||
constexpr auto Trim(StringView sv) -> StringView {
|
||||
constexpr auto Trim(StringView sview) -> StringView {
|
||||
using namespace std::ranges;
|
||||
|
||||
constexpr auto isSpace = [](const char character) { return std::isspace(static_cast<unsigned char>(character)); };
|
||||
|
||||
const borrowed_iterator_t<StringView&> start = find_if_not(sv, isSpace);
|
||||
const borrowed_iterator_t<reverse_view<StringView>> rstart = find_if_not(sv | views::reverse, isSpace);
|
||||
const borrowed_iterator_t<StringView&> start = find_if_not(sview, isSpace);
|
||||
const borrowed_iterator_t<reverse_view<StringView>> rstart = find_if_not(sview | views::reverse, isSpace);
|
||||
|
||||
return sv.substr(start - sv.begin(), sv.size() - (rstart - sv.rbegin()));
|
||||
return sview.substr(start - sview.begin(), sview.size() - (rstart - sview.rbegin()));
|
||||
}
|
||||
|
||||
fn GetX11WindowManager() -> String {
|
||||
const DisplayGuard display;
|
||||
using os::linux::XcbReplyGuard;
|
||||
using os::linux::XorgDisplayGuard;
|
||||
|
||||
if (!display)
|
||||
const XorgDisplayGuard conn;
|
||||
if (!conn)
|
||||
return "";
|
||||
|
||||
const Atom supportingWmCheck = XInternAtom(display.get(), "_NET_SUPPORTING_WM_CHECK", False);
|
||||
const Atom wmName = XInternAtom(display.get(), "_NET_WM_NAME", False);
|
||||
const Atom utf8String = XInternAtom(display.get(), "UTF8_STRING", False);
|
||||
fn internAtom = [&conn](const StringView name) -> XcbReplyGuard<xcb_intern_atom_reply_t> {
|
||||
const auto cookie = xcb_intern_atom(conn.get(), 0, static_cast<uint16_t>(name.size()), name.data());
|
||||
return XcbReplyGuard(xcb_intern_atom_reply(conn.get(), cookie, nullptr));
|
||||
};
|
||||
|
||||
const Window root = display.defaultRootWindow();
|
||||
const XcbReplyGuard<xcb_intern_atom_reply_t> supportingWmCheck = internAtom("_NET_SUPPORTING_WM_CHECK");
|
||||
const XcbReplyGuard<xcb_intern_atom_reply_t> wmName = internAtom("_NET_WM_NAME");
|
||||
const XcbReplyGuard<xcb_intern_atom_reply_t> utf8String = internAtom("UTF8_STRING");
|
||||
|
||||
Atom actualType = 0;
|
||||
i32 actualFormat = 0;
|
||||
u64 nitems = 0, bytesAfter = 0;
|
||||
u8* data = nullptr;
|
||||
if (!supportingWmCheck || !wmName || !utf8String)
|
||||
return "Unknown (X11)";
|
||||
|
||||
if (XGetWindowProperty(
|
||||
display.get(),
|
||||
root,
|
||||
supportingWmCheck,
|
||||
0,
|
||||
1,
|
||||
False,
|
||||
XA_WINDOW,
|
||||
&actualType,
|
||||
&actualFormat,
|
||||
&nitems,
|
||||
&bytesAfter,
|
||||
&data
|
||||
) == Success &&
|
||||
data) {
|
||||
const UniquePointer<u8, decltype(&XFree)> dataGuard(data, XFree);
|
||||
const xcb_window_t root = conn.rootScreen()->root;
|
||||
|
||||
u8* nameData = nullptr;
|
||||
fn getProperty = [&conn](
|
||||
const xcb_window_t window,
|
||||
const xcb_atom_t property,
|
||||
const xcb_atom_t type,
|
||||
const uint32_t offset,
|
||||
const uint32_t length
|
||||
) -> XcbReplyGuard<xcb_get_property_reply_t> {
|
||||
const xcb_get_property_cookie_t cookie = xcb_get_property(conn.get(), 0, window, property, type, offset, length);
|
||||
return XcbReplyGuard(xcb_get_property_reply(conn.get(), cookie, nullptr));
|
||||
};
|
||||
|
||||
if (XGetWindowProperty(
|
||||
display.get(),
|
||||
*reinterpret_cast<Window*>(data),
|
||||
wmName,
|
||||
0,
|
||||
1024,
|
||||
False,
|
||||
utf8String,
|
||||
&actualType,
|
||||
&actualFormat,
|
||||
&nitems,
|
||||
&bytesAfter,
|
||||
&nameData
|
||||
) == Success &&
|
||||
nameData) {
|
||||
const UniquePointer<u8, decltype(&XFree)> nameGuard(nameData, XFree);
|
||||
return reinterpret_cast<char*>(nameData);
|
||||
}
|
||||
}
|
||||
const XcbReplyGuard<xcb_get_property_reply_t> wmWindowReply =
|
||||
getProperty(root, supportingWmCheck->atom, XCB_ATOM_WINDOW, 0, 1);
|
||||
|
||||
return "Unknown (X11)";
|
||||
if (!wmWindowReply || wmWindowReply->type != XCB_ATOM_WINDOW || wmWindowReply->format != 32 ||
|
||||
xcb_get_property_value_length(wmWindowReply.get()) == 0)
|
||||
return "Unknown (X11)";
|
||||
|
||||
const xcb_window_t wmWindow = *static_cast<xcb_window_t*>(xcb_get_property_value(wmWindowReply.get()));
|
||||
|
||||
const XcbReplyGuard<xcb_get_property_reply_t> wmNameReply =
|
||||
getProperty(wmWindow, wmName->atom, utf8String->atom, 0, 1024);
|
||||
|
||||
if (!wmNameReply || wmNameReply->type != utf8String->atom || xcb_get_property_value_length(wmNameReply.get()) == 0)
|
||||
return "Unknown (X11)";
|
||||
|
||||
const char* nameData = static_cast<const char*>(xcb_get_property_value(wmNameReply.get()));
|
||||
const usize length = xcb_get_property_value_length(wmNameReply.get());
|
||||
|
||||
return { nameData, length };
|
||||
}
|
||||
|
||||
fn ReadProcessCmdline(const i32 pid) -> String {
|
||||
|
@ -124,6 +116,8 @@ namespace {
|
|||
}
|
||||
|
||||
fn GetWaylandCompositor() -> String {
|
||||
using os::linux::WaylandDisplayGuard;
|
||||
|
||||
if (const Option<String> hypr = DetectHyprlandSpecific())
|
||||
return *hypr;
|
||||
|
||||
|
|
|
@ -7,35 +7,36 @@
|
|||
#include "src/util/macros.h"
|
||||
|
||||
namespace os::linux {
|
||||
DisplayGuard::DisplayGuard(const CStr name) : m_Display(XOpenDisplay(name)) {}
|
||||
XorgDisplayGuard::XorgDisplayGuard(const CStr name) : m_Connection(xcb_connect(name, nullptr)) {}
|
||||
|
||||
DisplayGuard::~DisplayGuard() {
|
||||
if (m_Display)
|
||||
XCloseDisplay(m_Display);
|
||||
XorgDisplayGuard::~XorgDisplayGuard() {
|
||||
if (m_Connection)
|
||||
xcb_disconnect(m_Connection);
|
||||
}
|
||||
|
||||
DisplayGuard::DisplayGuard(DisplayGuard&& other) noexcept : m_Display(std::exchange(other.m_Display, nullptr)) {}
|
||||
XorgDisplayGuard::XorgDisplayGuard(XorgDisplayGuard&& other) noexcept
|
||||
: m_Connection(std::exchange(other.m_Connection, nullptr)) {}
|
||||
|
||||
fn DisplayGuard::operator=(DisplayGuard&& other) noexcept -> DisplayGuard& {
|
||||
fn XorgDisplayGuard::operator=(XorgDisplayGuard&& other) noexcept -> XorgDisplayGuard& {
|
||||
if (this != &other) {
|
||||
if (m_Display)
|
||||
XCloseDisplay(m_Display);
|
||||
|
||||
m_Display = std::exchange(other.m_Display, nullptr);
|
||||
if (m_Connection)
|
||||
xcb_disconnect(m_Connection);
|
||||
m_Connection = std::exchange(other.m_Connection, nullptr);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
DisplayGuard::operator bool() const { return m_Display != nullptr; }
|
||||
XorgDisplayGuard::operator bool() const { return m_Connection && !xcb_connection_has_error(m_Connection); }
|
||||
|
||||
fn DisplayGuard::get() const -> Display* { return m_Display; }
|
||||
fn XorgDisplayGuard::get() const -> xcb_connection_t* { return m_Connection; }
|
||||
|
||||
fn DisplayGuard::defaultRootWindow() const -> Window {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
return DefaultRootWindow(m_Display);
|
||||
#pragma clang diagnostic pop
|
||||
fn XorgDisplayGuard::setup() const -> const xcb_setup_t* {
|
||||
return m_Connection ? xcb_get_setup(m_Connection) : nullptr;
|
||||
}
|
||||
|
||||
fn XorgDisplayGuard::rootScreen() const -> xcb_screen_t* {
|
||||
const xcb_setup_t* setup = this->setup();
|
||||
return setup ? xcb_setup_roots_iterator(setup).data : nullptr;
|
||||
}
|
||||
|
||||
WaylandDisplayGuard::WaylandDisplayGuard() : m_Display(wl_display_connect(nullptr)) {}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <wayland-client.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
#include "src/util/macros.h"
|
||||
|
||||
|
@ -12,28 +12,70 @@ namespace os::linux {
|
|||
* RAII wrapper for X11 Display connections
|
||||
* Automatically handles resource acquisition and cleanup
|
||||
*/
|
||||
class DisplayGuard {
|
||||
Display* m_Display;
|
||||
class XorgDisplayGuard {
|
||||
xcb_connection_t* m_Connection = nullptr;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Opens an X11 display connection
|
||||
* Opens an XCB connection
|
||||
* @param name Display name (nullptr for default)
|
||||
*/
|
||||
explicit DisplayGuard(CStr name = nullptr);
|
||||
~DisplayGuard();
|
||||
explicit XorgDisplayGuard(CStr name = nullptr);
|
||||
~XorgDisplayGuard();
|
||||
|
||||
// Non-copyable
|
||||
DisplayGuard(const DisplayGuard&) = delete;
|
||||
fn operator=(const DisplayGuard&)->DisplayGuard& = delete;
|
||||
XorgDisplayGuard(const XorgDisplayGuard&) = delete;
|
||||
fn operator=(const XorgDisplayGuard&)->XorgDisplayGuard& = delete;
|
||||
|
||||
// Movable
|
||||
DisplayGuard(DisplayGuard&& other) noexcept;
|
||||
fn operator=(DisplayGuard&& other) noexcept -> DisplayGuard&;
|
||||
XorgDisplayGuard(XorgDisplayGuard&& other) noexcept;
|
||||
fn operator=(XorgDisplayGuard&& other) noexcept -> XorgDisplayGuard&;
|
||||
|
||||
[[nodiscard]] explicit operator bool() const;
|
||||
[[nodiscard]] fn get() const -> Display*;
|
||||
[[nodiscard]] fn defaultRootWindow() const -> Window;
|
||||
|
||||
[[nodiscard]] fn get() const -> xcb_connection_t*;
|
||||
[[nodiscard]] fn setup() const -> const xcb_setup_t*;
|
||||
[[nodiscard]] fn rootScreen() const -> xcb_screen_t*;
|
||||
};
|
||||
|
||||
/**
|
||||
* RAII wrapper for XCB replies
|
||||
* Handles automatic cleanup of various XCB reply objects
|
||||
*/
|
||||
template <typename T>
|
||||
class XcbReplyGuard {
|
||||
T* m_Reply = nullptr;
|
||||
|
||||
public:
|
||||
XcbReplyGuard() = default;
|
||||
explicit XcbReplyGuard(T* reply) : m_Reply(reply) {}
|
||||
|
||||
~XcbReplyGuard() {
|
||||
if (m_Reply)
|
||||
free(m_Reply);
|
||||
}
|
||||
|
||||
// Non-copyable
|
||||
XcbReplyGuard(const XcbReplyGuard&) = delete;
|
||||
fn operator=(const XcbReplyGuard&)->XcbReplyGuard& = delete;
|
||||
|
||||
// Movable
|
||||
XcbReplyGuard(XcbReplyGuard&& other) noexcept : m_Reply(std::exchange(other.m_Reply, nullptr)) {}
|
||||
fn operator=(XcbReplyGuard&& other) noexcept -> XcbReplyGuard& {
|
||||
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; }
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -59,8 +101,9 @@ namespace os::linux {
|
|||
fn operator=(WaylandDisplayGuard&& other) noexcept -> WaylandDisplayGuard&;
|
||||
|
||||
[[nodiscard]] explicit operator bool() const;
|
||||
[[nodiscard]] fn get() const -> wl_display*;
|
||||
[[nodiscard]] fn fd() const -> i32;
|
||||
|
||||
[[nodiscard]] fn get() const -> wl_display*;
|
||||
[[nodiscard]] fn fd() const -> i32;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue