From ea6bf62c9085b9a0c456078d2b7662db3a7f1e57 Mon Sep 17 00:00:00 2001 From: Mars Date: Tue, 18 Feb 2025 13:28:51 -0500 Subject: [PATCH] i think this is better --- flake.nix | 23 ++++--- meson.build | 3 +- src/main.cpp | 144 ++++++++++++++++++++++++++++++----------- src/os/macos.cpp | 13 ++-- src/os/macos/bridge.mm | 32 ++++----- 5 files changed, 143 insertions(+), 72 deletions(-) diff --git a/flake.nix b/flake.nix index e841796..2cfe86d 100644 --- a/flake.nix +++ b/flake.nix @@ -18,10 +18,13 @@ system: let pkgs = import nixpkgs {inherit system;}; - stdenv = - if pkgs.hostPlatform.isLinux - then pkgs.stdenvAdapters.useMoldLinker pkgs.llvmPackages_19.stdenv - else pkgs.llvmPackages_19.stdenv; + stdenv = with pkgs; + ( + if hostPlatform.isLinux + then stdenvAdapters.useMoldLinker + else lib.id + ) + llvmPackages_19.stdenv; sources = import ./_sources/generated.nix { inherit (pkgs) fetchFromGitHub fetchgit fetchurl dockerTools; @@ -71,17 +74,17 @@ ++ linuxPkgs ++ darwinPkgs; - linuxPkgs = - nixpkgs.lib.optionals stdenv.isLinux (with pkgs; [ + linuxPkgs = nixpkgs.lib.optionals stdenv.isLinux (with pkgs; + [ pkgsStatic.glib systemdLibs sdbus-cpp valgrind xorg.libX11 - ]) - ++ (with pkgs.pkgsStatic; [ + ] + ++ (with pkgsStatic; [ wayland - ]); + ])); darwinPkgs = nixpkgs.lib.optionals stdenv.isDarwin (with pkgs.pkgsStatic.darwin.apple_sdk.frameworks; [ Foundation @@ -156,7 +159,7 @@ ] ++ deps; - LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath deps}"; + LD_LIBRARY_PATH = "${lib.makeLibraryPath deps}"; name = "C++"; }; diff --git a/meson.build b/meson.build index f01495d..de03fe2 100644 --- a/meson.build +++ b/meson.build @@ -48,6 +48,7 @@ common_cpp_args = [ '-Wno-switch-default', '-Wunused-function', '-fvisibility=hidden', + '-fno-strict-enums', ] if host_machine.system() == 'windows' @@ -114,4 +115,4 @@ executable( objc_args: objc_args, link_args: link_args, dependencies: deps, -) \ No newline at end of file +) diff --git a/src/main.cpp b/src/main.cpp index a6577c4..077e092 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "config/config.h" @@ -23,11 +24,13 @@ constexpr u64 GIB = 1'073'741'824; template <> struct fmt::formatter : fmt::formatter { template - constexpr auto format(const BytesToGiB& BTG, FmtCtx& ctx) const -> typename FmtCtx::iterator { - auto out = fmt::formatter::format(static_cast(BTG.value) / GIB, ctx); - *out++ = 'G'; - *out++ = 'i'; - *out++ = 'B'; + constexpr fn format(const BytesToGiB& BTG, FmtCtx& ctx) const -> typename FmtCtx::iterator { + typename FmtCtx::iterator out = fmt::formatter::format(static_cast(BTG.value) / GIB, ctx); + + *out++ = 'G'; + *out++ = 'i'; + *out++ = 'B'; + return out; } }; @@ -35,8 +38,16 @@ struct fmt::formatter : fmt::formatter { namespace { fn GetDate() -> std::string { // Get current local time - std::time_t now = std::time(nullptr); - std::tm localTime = *std::localtime(&now); + std::time_t now = std::time(nullptr); + std::tm localTime; + +#ifdef __WIN32__ + if (localtime_s(&localTime, &now) != 0) + ERROR_LOG("localtime_s failed"); +#else + if (localtime_r(&now, &localTime) == nullptr) + ERROR_LOG("localtime_r failed"); +#endif // Format the date using fmt::format std::string date = fmt::format("{:%e}", localTime); @@ -58,6 +69,63 @@ namespace { return fmt::format("{:%B} {}", localTime, date); } + struct SystemData { + std::string date; + std::string host; + std::string kernel_version; + std::string os_version; + std::expected mem_info; + std::string desktop_environment; + std::string window_manager; + std::optional now_playing; + std::optional weather_info; + + static fn fetchSystemData(const Config& config) -> SystemData { + SystemData data; + + std::launch launchPolicy = std::launch::async | std::launch::deferred; + + if (std::thread::hardware_concurrency() >= 8) + launchPolicy = std::launch::async; + + // Launch async tasks + std::future futureDate = std::async(launchPolicy, GetDate); + std::future futureHost = std::async(launchPolicy, GetHost); + std::future futureKernel = std::async(launchPolicy, GetKernelVersion); + std::future futureOs = std::async(launchPolicy, GetOSVersion); + std::future> futureMem = std::async(launchPolicy, GetMemInfo); + std::future futureDe = std::async(launchPolicy, GetDesktopEnvironment); + std::future futureWm = std::async(launchPolicy, GetWindowManager); + + std::future futureWeather; + + if (config.weather.get().enabled) + futureWeather = std::async(std::launch::async, [&config]() { return config.weather.get().getWeatherInfo(); }); + + std::future futureNowPlaying; + + if (config.now_playing.get().enabled) + futureNowPlaying = std::async(std::launch::async, GetNowPlaying); + + // Collect results + data.date = futureDate.get(); + data.host = futureHost.get(); + data.kernel_version = futureKernel.get(); + data.os_version = futureOs.get(); + data.mem_info = futureMem.get(); + data.desktop_environment = futureDe.get(); + data.window_manager = futureWm.get(); + + if (config.weather.get().enabled) + data.weather_info = futureWeather.get(); + + if (config.now_playing.get().enabled) + data.now_playing = futureNowPlaying.get(); + + return data; + } + }; + using namespace ftxui; fn CreateColorCircles() -> Element { @@ -72,19 +140,11 @@ namespace { return hbox(circles); } - fn SystemInfoBox(const Config& config) -> Element { + fn SystemInfoBox(const Config& config, const SystemData& data) -> Element { // Fetch data - const string& name = config.general.get().name.get(); - const string& date = GetDate(); - const Weather weather = config.weather.get(); - const string& host = GetHost(); - const string& kernelVersion = GetKernelVersion(); - const string& osVersion = GetOSVersion(); - const u64 memInfo = GetMemInfo().value_or(0); - const string& desktopEnvironment = GetDesktopEnvironment(); - const string& windowManager = GetWindowManager(); - const bool nowPlayingEnabled = config.now_playing.get().enabled; - const string& nowPlaying = nowPlayingEnabled ? GetNowPlaying() : ""; + const string& name = config.general.get().name.get(); + const Weather weather = config.weather.get(); + const bool nowPlayingEnabled = config.now_playing.get().enabled; const char *calendarIcon = "", *hostIcon = "", *kernelIcon = "", *osIcon = "", *memoryIcon = "", *weatherIcon = "", *musicIcon = ""; @@ -115,7 +175,7 @@ namespace { content.push_back(separator() | color(borderColor)); // Helper function for aligned rows - auto createRow = [&](const std::string& icon, const std::string& label, const std::string& value) { + fn createRow = [&](const std::string& icon, const std::string& label, const std::string& value) { return hbox({ text(icon) | color(iconColor), text(label) | color(labelColor), @@ -126,11 +186,11 @@ namespace { }; // System info rows - content.push_back(createRow(calendarIcon, "Date", date)); + content.push_back(createRow(calendarIcon, "Date", data.date)); // Weather row - if (weather.enabled) { - WeatherOutput weatherInfo = weather.getWeatherInfo(); + if (weather.enabled && data.weather_info.has_value()) { + const WeatherOutput& weatherInfo = data.weather_info.value(); if (weather.show_town_name) content.push_back(hbox({ @@ -162,35 +222,41 @@ namespace { content.push_back(separator() | color(borderColor)); - if (!host.empty()) - content.push_back(createRow(hostIcon, "Host", host)); + if (!data.host.empty()) + content.push_back(createRow(hostIcon, "Host", data.host)); - if (!kernelVersion.empty()) - content.push_back(createRow(kernelIcon, "Kernel", kernelVersion)); + if (!data.kernel_version.empty()) + content.push_back(createRow(kernelIcon, "Kernel", data.kernel_version)); - if (!osVersion.empty()) - content.push_back(createRow(osIcon, "OS", osVersion)); + if (!data.os_version.empty()) + content.push_back(createRow(osIcon, "OS", data.os_version)); - if (memInfo > 0) - content.push_back(createRow(memoryIcon, "RAM", fmt::format("{:.2f}", BytesToGiB { memInfo }))); + if (data.mem_info.has_value()) + content.push_back(createRow(memoryIcon, "RAM", fmt::format("{:.2f}", BytesToGiB { data.mem_info.value() }))); + else + ERROR_LOG("Failed to get memory info: {}", data.mem_info.error()); content.push_back(separator() | color(borderColor)); - if (!desktopEnvironment.empty() && desktopEnvironment != windowManager) - content.push_back(createRow(" 󰇄 ", "DE", desktopEnvironment)); + if (!data.desktop_environment.empty() && data.desktop_environment != data.window_manager) + content.push_back(createRow(" 󰇄 ", "DE", data.desktop_environment)); - if (!windowManager.empty()) - content.push_back(createRow("  ", "WM", windowManager)); + if (!data.window_manager.empty()) + content.push_back(createRow("  ", "WM", data.window_manager)); // Now Playing row - if (nowPlayingEnabled && !nowPlaying.empty()) { + if (nowPlayingEnabled && data.now_playing.has_value()) { content.push_back(separator() | color(borderColor)); content.push_back(hbox({ text(musicIcon) | color(iconColor), text("Music") | color(labelColor), text(" "), filler(), - text(nowPlaying.length() > 30 ? nowPlaying.substr(0, 30) + "..." : nowPlaying) | color(Color::Magenta), + text( + data.now_playing.value().length() > 30 ? data.now_playing.value().substr(0, 30) + "..." + : data.now_playing.value() + ) | + color(Color::Magenta), text(" "), })); } @@ -202,7 +268,9 @@ namespace { fn main() -> i32 { const Config& config = Config::getInstance(); - Element document = hbox({ SystemInfoBox(config), filler() }); + SystemData data = SystemData::fetchSystemData(config); + + Element document = hbox({ SystemInfoBox(config, data), filler() }); Screen screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); diff --git a/src/os/macos.cpp b/src/os/macos.cpp index d660816..45ad334 100644 --- a/src/os/macos.cpp +++ b/src/os/macos.cpp @@ -1,17 +1,18 @@ #ifdef __APPLE__ +#include #include #include -#include #include "macos/bridge.h" #include "os.h" -fn GetMemInfo() -> u64 { +fn GetMemInfo() -> std::expected { u64 mem = 0; usize size = sizeof(mem); - sysctlbyname("hw.memsize", &mem, &size, nullptr, 0); + if (sysctlbyname("hw.memsize", &mem, &size, nullptr, 0) == -1) + return std::unexpected(std::string("sysctlbyname failed: ") + strerror(errno)); return mem; } @@ -27,9 +28,11 @@ fn GetOSVersion() -> string { return GetMacOSVersion(); } fn GetDesktopEnvironment() -> string { return "Aqua"; } +fn GetWindowManager() -> string { return "Yabai"; } + fn GetKernelVersion() -> string { std::array kernelVersion; - size_t kernelVersionLen = sizeof(kernelVersion); + usize kernelVersionLen = sizeof(kernelVersion); sysctlbyname("kern.osrelease", kernelVersion.data(), &kernelVersionLen, nullptr, 0); @@ -42,7 +45,7 @@ fn GetHost() -> string { sysctlbyname("hw.model", hwModel.data(), &hwModelLen, nullptr, 0); - // shamelessly stolen from https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/host/host_mac.c + // taken from https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/host/host_mac.c // shortened a lot of the entries to remove unnecessary info std::map modelNameByHwModel = { // MacBook Pro diff --git a/src/os/macos/bridge.mm b/src/os/macos/bridge.mm index 2ed991a..70a26ed 100644 --- a/src/os/macos/bridge.mm +++ b/src/os/macos/bridge.mm @@ -5,20 +5,19 @@ #import "bridge.h" +#include "../../util/macros.h" + using MRMediaRemoteGetNowPlayingInfoFunction = void (*)(dispatch_queue_t queue, void (^handler)(NSDictionary* information)); @implementation Bridge + (NSDictionary*)currentPlayingMetadata { CFURLRef ref = CFURLCreateWithFileSystemPath( - kCFAllocatorDefault, - CFSTR("/System/Library/PrivateFrameworks/MediaRemote.framework"), - kCFURLPOSIXPathStyle, - false + kCFAllocatorDefault, CFSTR("/System/Library/PrivateFrameworks/MediaRemote.framework"), kCFURLPOSIXPathStyle, false ); if (!ref) { - NSLog(@"Failed to load MediaRemote framework"); + ERROR_LOG("Failed to load MediaRemote framework"); return nil; } @@ -26,17 +25,16 @@ using MRMediaRemoteGetNowPlayingInfoFunction = CFRelease(ref); if (!bundle) { - NSLog(@"Failed to load MediaRemote framework"); + ERROR_LOG("Failed to load MediaRemote framework"); return nil; } - MRMediaRemoteGetNowPlayingInfoFunction mrMediaRemoteGetNowPlayingInfo = - reinterpret_cast( - CFBundleGetFunctionPointerForName(bundle, CFSTR("MRMediaRemoteGetNowPlayingInfo")) - ); + auto mrMediaRemoteGetNowPlayingInfo = std::bit_cast( + CFBundleGetFunctionPointerForName(bundle, CFSTR("MRMediaRemoteGetNowPlayingInfo")) + ); if (!mrMediaRemoteGetNowPlayingInfo) { - NSLog(@"Failed to get function pointer for MRMediaRemoteGetNowPlayingInfo"); + ERROR_LOG("Failed to get function pointer for MRMediaRemoteGetNowPlayingInfo"); CFRelease(bundle); return nil; } @@ -55,6 +53,7 @@ using MRMediaRemoteGetNowPlayingInfoFunction = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); CFRelease(bundle); + return nowPlayingInfo; } @@ -63,15 +62,12 @@ using MRMediaRemoteGetNowPlayingInfoFunction = NSOperatingSystemVersion osVersion = [processInfo operatingSystemVersion]; - NSString* version; + NSString* version = nullptr; if (osVersion.patchVersion == 0) { - version = - [NSString stringWithFormat:@"%ld.%ld", osVersion.majorVersion, osVersion.minorVersion]; + version = [NSString stringWithFormat:@"%ld.%ld", osVersion.majorVersion, osVersion.minorVersion]; } else { - version = [NSString stringWithFormat:@"%ld.%ld.%ld", - osVersion.majorVersion, - osVersion.minorVersion, - osVersion.patchVersion]; + version = [NSString + stringWithFormat:@"%ld.%ld.%ld", osVersion.majorVersion, osVersion.minorVersion, osVersion.patchVersion]; } // Dictionary to map macOS versions to their respective names