diff --git a/.clang-tidy b/.clang-tidy index da712a4..198b03f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -5,6 +5,7 @@ Checks: > -altera-*, -bugprone-easily-swappable-parameters, -bugprone-implicit-widening-of-multiplication-result, + -cert-env33-c, -concurrency-mt-unsafe, -cppcoreguidelines-avoid-magic-numbers, -cppcoreguidelines-owning-memory, diff --git a/flake.lock b/flake.lock index ccfecf5..42cb612 100644 --- a/flake.lock +++ b/flake.lock @@ -246,11 +246,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1722375055, - "narHash": "sha256-TXtpKGKpaa7ZivMgB0y+63ZLITXPXIAzof6hqw1pqHA=", + "lastModified": 1722885831, + "narHash": "sha256-LZ2AUNCIsp8Sr5cTELR1VmdrWCzuq8B9t24dGWqQs9w=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d8c09e3ff18ad95f0765fdfc21f4698dea7ab670", + "rev": "6696fd5d8cf6c25387f02327941d2e6e47df6947", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index fcd9f3c..e041736 100644 --- a/flake.nix +++ b/flake.nix @@ -35,10 +35,13 @@ }; fmt = mkPkg "fmt"; - sdbus-cpp = mkPkg "sdbus-cpp"; tomlplusplus = mkPkg "tomlplusplus"; yyjson = mkPkg "yyjson"; + sdbus-cpp = pkgs.sdbus-cpp.overrideAttrs { + inherit (sources.sdbus-cpp) pname version src; + }; + reflect-cpp = stdenv.mkDerivation { inherit (sources.reflect-cpp) pname version src; @@ -68,6 +71,7 @@ systemdLibs sdbus-cpp valgrind + xorg.libX11 ]); darwinPkgs = nixpkgs.lib.optionals stdenv.isDarwin (with pkgs.pkgsStatic.darwin.apple_sdk.frameworks; [ diff --git a/meson.build b/meson.build index 074043d..f56662b 100644 --- a/meson.build +++ b/meson.build @@ -9,8 +9,6 @@ project( ] ) -clangtidy = find_program('clang-tidy', required: false) - cpp = meson.get_compiler('cpp') if host_machine.system() == 'darwin' @@ -94,6 +92,7 @@ if host_machine.system() == 'darwin' deps += dependency('iconv') elif host_machine.system() == 'linux' deps += dependency('sdbus-c++') + deps += dependency('x11') endif objc_args = [] diff --git a/src/os/linux.cpp b/src/os/linux.cpp index bc2b0f1..117dd0f 100644 --- a/src/os/linux.cpp +++ b/src/os/linux.cpp @@ -1,5 +1,7 @@ #ifdef __linux__ +#include +#include #include #include #include @@ -9,6 +11,8 @@ #include "os.h" +enum SessionType { Wayland, X11, TTY, Unknown }; + fn ParseLineAsNumber(const string& input) -> u64 { // Find the first number string::size_type start = 0; @@ -134,4 +138,137 @@ fn GetNowPlaying() -> string { return ""; } +fn GetDesktopEnvironment() -> string { + const char* xdgCurrentDesktop = std::getenv("XDG_CURRENT_DESKTOP"); + + if (xdgCurrentDesktop) + return xdgCurrentDesktop; + + return std::getenv("DESKTOP_SESSION"); +} + +fn GetSessionType() -> SessionType { + string xdgSessionType = std::getenv("XDG_SESSION_TYPE"); + + if (xdgSessionType == "wayland") + return Wayland; + if (xdgSessionType == "x11") + return X11; + if (xdgSessionType == "tty") + return TTY; + return Unknown; +} + +fn Exec(const char* cmd) -> string { + std::array buffer; + std::string result; + std::unique_ptr pipe(popen(cmd, "r"), pclose); + + if (!pipe) { + throw std::runtime_error("popen() failed!"); + } + + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { result += buffer.data(); } + + return result; +} + +fn GetWindowManager() -> string { + string xdgSessionType = std::getenv("XDG_SESSION_TYPE"); + + if (xdgSessionType == "wayland") { + // TODO implement wayland window manager + } + + if (xdgSessionType == "x11") { + Display* display = XOpenDisplay(nullptr); + + Atom wmCheckAtom = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", True); + if (wmCheckAtom == None) { + return "Unknown (no _NET_SUPPORTING_WM_CHECK)"; + } + + Window root = DefaultRootWindow(display); + Atom actualType = 0; + int actualFormat = 0; + unsigned long itemCount = 0, bytesAfter = 0; + unsigned char* data = nullptr; + + int status = XGetWindowProperty( + display, + root, + wmCheckAtom, + 0, + 1, + False, + XA_WINDOW, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + &data + ); + if (status != Success || !data) { + return "Unknown (failed to get _NET_SUPPORTING_WM_CHECK)"; + } + + Window wmWindow = *(Window*)(data); + XFree(data); + + status = XGetWindowProperty( + display, + wmWindow, + wmCheckAtom, + 0, + 1, + False, + XA_WINDOW, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + &data + ); + if (status != Success || !data) { + return "Unknown (failed to get supporting window)"; + } + + wmWindow = *(reinterpret_cast(data)); + XFree(data); + + Atom wmNameAtom = XInternAtom(display, "_NET_WM_NAME", True); + if (wmNameAtom == None) { + return "Unknown (no _NET_WM_NAME)"; + } + + status = XGetWindowProperty( + display, + wmWindow, + wmNameAtom, + 0, + (~0L), + False, + AnyPropertyType, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + &data + ); + if (status != Success || !data) { + return "Unknown (failed to get _NET_WM_NAME)"; + } + + std::string wmName(reinterpret_cast(data)); + XFree(data); + + return wmName; + } + + if (xdgSessionType == "tty") + return "TTY"; + + return "Unknown"; +} + #endif diff --git a/src/os/macos.cpp b/src/os/macos.cpp index a1bf297..e8bc12b 100644 --- a/src/os/macos.cpp +++ b/src/os/macos.cpp @@ -23,4 +23,6 @@ fn GetNowPlaying() -> string { fn GetOSVersion() -> string { return GetMacOSVersion(); } +fn GetDesktopEnvironment() -> string { return "Aqua"; } + #endif diff --git a/src/os/os.h b/src/os/os.h index 076dfc1..0235933 100644 --- a/src/os/os.h +++ b/src/os/os.h @@ -17,3 +17,13 @@ fn GetNowPlaying() -> string; * @brief Get the OS version. */ fn GetOSVersion() -> string; + +/** + * @brief Get the current desktop environment. + */ +fn GetDesktopEnvironment() -> string; + +/** + * @brief Get the current window manager. + */ +fn GetWindowManager() -> string;